WKWebView carga recursos desde la carpeta del documento local

En mi aplicación Swift para iOS, deseo descargar algunas páginas HTML dinámicas de un servidor remoto, guardarlas en el directorio de documentos y visualizar esas páginas desde el directorio de documentos.

Estaba usando esto para cargar la página:

var appWebView:WKWebView? ... appWebView!.loadRequest(NSURLRequest(URL: NSURL(fileURLWithPath: htmlPath))) 

Todo funciona en el simulador, pero cuando me mudé a teléfonos reales, simplemente mostró una página en blanco. Luego me conecté a la aplicación usando Safari, y encontré que se quejó con “Error al cargar el recurso”.

Luego intenté leer primero el contenido de la página en htmlPath , luego usar

 appWebView!.loadHTMLString() 

para cargar la página Funciona cuando la página HTML es simple. Pero si el HTML hace referencia a algo más, es decir, un archivo JavaScript también en el directorio del documento (con una ruta absoluta como ), no se cargará.

¿Alguien sabe por qué sucede esto y cómo resolver el problema?

Más información:

  • Versión XCode: 7.3.1
  • Destino de despliegue: 8.1 (Traté de usar 9.3 también, pero eso no ayudó).

Esta es una versión simplificada de lo que he usado para cargar archivos locales en un proyecto mío (iOS 10, Swift 3). Acabo de actualizar mi código (7.5.2017) después de probarlo de nuevo en iOS 10.3.1 y iPhone 7+ según lo solicitado por Raghuram y Fox5150 en los comentarios.

Acabo de crear un proyecto completamente nuevo y esta es la estructura de la carpeta: enter image description here

Actualización 19.04.2018: Se agregó una nueva función para descargar un .zip con HTML, CSS, archivos JS, descomprimirlo en / Documents / (Alamofire + Zip) y luego cargar esos archivos en la webView. Puede encontrarlo en el proyecto de ejemplo GitHub también. De nuevo, ¡siéntase libre de bifurcar y protagonizar! 🙂

Actualización 08.02.2018: finalmente se agregó un proyecto de ejemplo de GitHub , que también incluye un archivo JavaScript local. Siéntase libre de tenedor y estrella! 🙂

Versión 1 con webView.loadFileURL ()

ViewController.swift

 import UIKit import WebKit class ViewController: UIViewController, WKNavigationDelegate { override func viewDidLoad() { super.viewDidLoad() let webView = WKWebView() let htmlPath = Bundle.main.path(forResource: "index", ofType: "html") let htmlUrl = URL(fileURLWithPath: htmlPath!, isDirectory: false) webView.loadFileURL(htmlUrl, allowingReadAccessTo: htmlUrl) webView.navigationDelegate = self view = webView } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } } 

Versión 2 con webView.loadHTMLString ()

ViewController.swift

 import UIKit import WebKit class ViewController: UIViewController, WKNavigationDelegate { override func viewDidLoad() { super.viewDidLoad() let webView = WKWebView() let htmlPath = Bundle.main.path(forResource: "index", ofType: "html") let folderPath = Bundle.main.bundlePath let baseUrl = URL(fileURLWithPath: folderPath, isDirectory: true) do { let htmlString = try NSString(contentsOfFile: htmlPath!, encoding: String.Encoding.utf8.rawValue) webView.loadHTMLString(htmlString as String, baseURL: baseUrl) } catch { // catch error } webView.navigationDelegate = self view = webView } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } } 

Gotchas para tener en cuenta:

  • Asegúrese de que sus archivos html / js / css locales estén en Proyecto -> Destino -> Fases de comstackción -> Copiar recursos de paquete
  • Asegúrese de que sus archivos html no hagan referencia a las rutas relativas, por ejemplo, css/styles.css ya que iOS css/styles.css la estructura de su archivo y styles.css estará en el mismo nivel que index.html, por lo tanto, escriba lugar

Dadas las 2 versiones y los errores aquí están mis archivos html / css del proyecto:

web / index.html

     Offline WebKit    

Offline WebKit!

web / css / styles.css

 #webkit-h1 { font-size: 80px; color: lightblue; } 

Si alguien quiere un proyecto de ejemplo de GitHub, dígamelo en la sección de comentarios y lo subiré.

Método Swift 4

Este método permite a WKWebView leer correctamente su jerarquía de directorios y subdirectorios para archivos CSS / JS vinculados. NO es necesario que cambie su código HTML, CSS o JS.

Actualizado para Xcode 9.3

Paso 1

Importe la carpeta de archivos web locales en cualquier lugar de su proyecto. Asegúrate de:

Xcode/> Archivo> Agregar archivos a “Proyecto””> </p>
<blockquote>
<p>  Copy️ Copie los artículos si es necesario </p>
<p>  Create️ <strong>Crear referencias de carpeta</strong> <em>(no “Crear grupos”)</em> </p>
<p>  Add Añadir a los objectives </p>
</blockquote>
<h2>  Paso 2 </h2>
<p>  Vaya a View Controller con WKWebView y agregue el siguiente código al método <code>viewDidLoad</code> : </p>
<pre> <code>let url = Bundle.main.url(forResource:

  • index – el nombre del archivo a cargar (sin la extensión .html )
  • website : el nombre de su carpeta web ( index.html debe estar en la raíz de este directorio)

Conclusión

El código general debería verse más o menos así:

 import UIKit import WebKit class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate { @IBOutlet weak var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() webView.uiDelegate = self webView.navigationDelegate = self let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "Website")! webView.loadFileURL(url, allowingReadAccessTo: url) let request = URLRequest(url: url) webView.load(request) } } 

Si alguno de ustedes tiene más preguntas sobre este método o el código, haré todo lo posible para responder. 🙂

Esta solución me ayudó:

 [configuration.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"]; 

Esto funciona bien (Swift 3, Xcode 8):

 import UIKit import WebKit class ViewController: UIViewController, WKNavigationDelegate { var webView: WKWebView! override func loadView() { webView = WKWebView() webView.navigationDelegate = self view = webView } override func viewDidLoad() { super.viewDidLoad() if let url = Bundle.main.url(forResource: "file", withExtension: "txt") { do { let contents = try String(contentsOfFile: url.path) webView.loadHTMLString(contents, baseURL: url.deletingLastPathComponent()) } catch { print("Could not load the HTML string.") } } } }