support previous objective broken before ios css swift image wkwebview

ios - previous - wkwebview objective c



WKWebView no puede cargar imágenes y CSS usando loadHTMLString(_, baseURL:) (8)

La recomendación de Apple :

En aplicaciones que se ejecutan en iOS 8 y versiones posteriores, use la clase WKWebView en lugar de usar UIWebView.

Por lo tanto, he reemplazado mi viejo UIWebView viejo UIWebView con un nuevo y brillante WKWebView . Pero lo que pensé que era un ejercicio fácil (simplemente intercambiar las clases y reemplazar los métodos de delegado) resultó ser un verdadero desastre.

El problema

Cuando carga una cadena HTML usando

loadHTMLString(String, baseURL: URL?)

La vista web carga y reproduce el HTML puro, pero no carga ninguna imagen o archivo CSS al que se hace referencia dentro de la htmlString .

¡Esto sucede solo en un dispositivo real !
En Simultor todos los recursos referenciados se cargan correctamente.

Ejemplo

He definido un htmlString simple en mi clase de controlador de vista:

let imageName = "image.png" let libraryURL: URL // The default Library URL var htmlString: String { return "<html> ... <img src=/"/(imageName)/" /> ... </html>" // "..." represents more valid HTML code incl. header and body tags }

La imagen se almacena en la carpeta de la biblioteca raíz, por lo que su URL es:

let imageURL = libraryURL.appendingPathComponent(imageName)

Ahora cargo el htmlString en la vista web:

webView.loadHTMLString(htmlString, baseURL: libraryURL)

y no carga la imagen a pesar de que la baseURL está configurada correctamente.

Ideas para una solución

  1. Tal vez WKWebView tenga un problema con la resolución de rutas relativas, por lo que mi primera idea fue utilizar rutas absolutas dentro de la cadena HTML.
    → ❌ No funciona.

  2. Dos respuestas a otra publicación SO sugirieron que usar
    loadFileURL(URL, allowingReadAccessTo: URL)
    En lugar de loadHTMLString(...) funciona en iOS 9+.
    → ✅ Eso funciona.

Sin embargo, no puedo usar la solución 2 porque mis archivos HTML están cifrados y los archivos descifrados no deben almacenarse en el disco.

Pregunta

¿Hay alguna forma de cargar recursos locales como imágenes y estilos usando el WKWebView ''s

loadHTMLString(String, baseURL: URL?)

¿función? ¿O sigue siendo un error en iOS 9+?

(¡¿No puedo creer que Apple proporcione y recomiende usar una vista web que no pueda cargar ningún contenido web local desde una cadena HTML ?!)


Bueno, debería poder usar imágenes locales y archivos CSS (y archivos JavaScript para esa materia) con WKWebViews con la función que ya ha encontrado. Mi conjetura es que el problema está con su variable baseURL .

Actualización 7.5.2017:

He actualizado completamente el código de otra SO de respuesta mía que solía estar vinculado a mi respuesta aquí. Tengo un proyecto de trabajo para loadHTMLString() y .loadFileURL()


Hoy tuve este problema, encontré la solución y potencialmente la causa:

loadHTMLString(String, baseURL: URL?)

Esta función no permite que el HTML representado acceda a los medios locales, que yo sepa, esto se debe a que sería un riesgo de inyección, esto podría permitir que el HTML procesado acceda y manipule su sistema de archivos local. Con una cadena html, eso podría venir de cualquier parte o de cualquiera.

loadFileURL(URL, allowingReadAccessTo: URL)

Con esta función, apunta el WKWebview al archivo html en su FileManager, y a la carpeta que contiene con ''allowReadAccessTo''. Debido a que el html está almacenado dentro del Administrador de archivos, permitirá que el HTML renderizado acceda a los medios almacenados localmente.

Si no tiene el archivo html almacenado localmente por algún motivo (supongo que sí), puede escribir la cadena html en un archivo .html y luego apuntar a la URL de ese archivo. Sin embargo, esto solo está subvirtiendo la protección de Apple, así que hazlo bajo tu propio riesgo (no lo hagas).

Esta es solo la solución que funcionó para mí y mi comprensión de por qué tenemos el problema, para empezar.


Intenta crear baseURL usando:

let baseURL = URL(fileURLWithPath: "#path#")

en lugar de:

let baseURL = URL(string: "#path#")

La principal diferencia es que el primer método agrega file:// prefijo file:// antes de la ruta.


Personalmente, tuve que cambiar a usar XWebView porque el comportamiento de WKWebView no permite cargar archivos locales. XWebView lo engaña cargando un servidor web local en segundo plano y dirigiendo el tráfico local a través de él. (XWebView se basa en la parte superior de WKWebView)

Parece un poco exagerado, pero eso es lo que terminé por tener que hacer.


Pude reproducir un problema similar. WKWebView carga mis imágenes especialmente si están ubicadas de forma remota, aparte de mi servidor de aplicaciones.

Para los servidores que no tienen info.plist SSL (http en lugar de https), puede configurar su info.plist siguiente manera:

App Transport Security Settings - Allow Arbitrary Loads in Web Content (Set to YES) - Allow Arbitrary Loads (Set to YES)

El problema estaba realmente en el servidor. La aplicación del servidor era:

  • Cambiando la "http://IP-or-domain/uploads/file.jpg" src de "http://IP-or-domain/uploads/file.jpg" a "../../uploads/file.jpg"

- O -

  • La imagen src era "http://localhost/uploads/file.jpg" o "http://127.0.0.1/uploads/file.jpg" lugar de "http://YOUR-SERVER-IP-ADDRESS/uploads/file.jpg"

En estos casos, el dispositivo real no podrá localizar la imagen. Esto solo funciona con el simulador de iOS porque el dispositivo virtual es el mismo que el servidor y la máquina de desarrollo. Puede leer LOCALHOST y 127.0.0.1 .

En mi servidor, estaba usando un editor de texto enriquecido (TinyMCE) y elimina automáticamente la dirección IP después de detectar que es la misma fuente.


Puedes codificar en base64 las imágenes ... Sé que funciona. No estoy seguro si será apropiado para su caso de uso sin embargo.

Algo gracioso, me encontré con este problema mientras hacía lo contrario: pasar de base64 codificado a archivos de imagen.


Sin echar un vistazo a su proyecto real, es difícil dar un ciento por ciento de consejos seguros.

Sin embargo:

class ViewController: UIViewController { var webView = WKWebView() override func viewDidLoad() { super.viewDidLoad() webView.translatesAutoresizingMaskIntoConstraints = false let views = [ "webView" : webView ] view.addSubview(webView) var constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: [.AlignAllLeading, .AlignAllTrailing], metrics: nil, views: views) constraints.appendContentsOf(NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options: [.AlignAllTop, .AlignAllBottom], metrics: nil, views: views)) NSLayoutConstraint.activateConstraints(constraints) let path = NSBundle.mainBundle().pathForResource("ios - WKWebView fails to load images and CSS using loadHTMLString(_, baseURL_) - ", ofType: "htm") let url = NSURL(fileURLWithPath: path!) webView.loadHTMLString(try! String(contentsOfURL: url), baseURL: url.URLByDeletingLastPathComponent) // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }

Creo que el punto clave aquí es el parámetro baseUrl , debe configurarlo correctamente. En mi caso, he usado la URL de html sin el último componente de ruta, por ejemplo, que contiene la carpeta. Esto funciona bien tanto en el dispositivo como en el simulador: verifique la instantánea del dispositivo. He cargado un proyecto de muestra en https://github.com/soxjke/WKWebViewTest para que pueda echar un vistazo (he eliminado la información de firma de códigos de git)

Entonces, para recapitular: el método funciona, la funcionalidad funciona, solo haces algo mal con él. Para ayudarlo a comprender qué problemas tienen con sus soluciones, agregaré algunas sugerencias: 1. Recuerde que el sistema de archivos del simulador no distingue entre mayúsculas y minúsculas , el sistema de archivos del dispositivo distingue entre mayúsculas y minúsculas . Entonces, si tiene sus nombres de archivo en html en minúsculas, esto no funcionará en el dispositivo. 8fFsD.png != 8ffsd.png 2. Recuerde que al copiar recursos, XCode ignora la estructura de su carpeta. Entonces, si su html tiene <img src="./img/1.png"> y su proyecto XCOde tiene una estructura de carpetas como

test.htm img/ 1.png 2.png

Después de la compilación, se aplanará, por lo que test.htm y 1.png y 2.png residirán en el mismo nivel

test.htm 1.png 2.png

Estoy casi seguro de que, después de verificar estas dos suposiciones, este método funcionará.


También he estado experimentando con esto, con restricciones similares, y el problema parece ser que las rutas no se resuelven a menos que baseURL haga referencia al paquete de la aplicación. No funciona si, por ejemplo, tiene algo en los documentos de la aplicación.

Edit: he archivado un radar para este rdar://29130863