web-dev-qa-db-fra.com

WKWebView charge les ressources du dossier de document local

Dans mon application Swift iOS, je souhaite télécharger des pages HTML dynamiques à partir d'un serveur distant, les enregistrer dans le répertoire de documents et afficher ces pages à partir du répertoire de documents.

J'utilisais ceci pour charger la page:

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

Tout fonctionne sur le simulateur, mais lorsque je me suis installé sur de vrais téléphones, une page vierge s’est affichée. Je me suis ensuite connecté à l'application à l'aide de Safari et j'ai constaté qu'il se plaint de "Impossible de charger la ressource".

J'ai ensuite essayé de lire d'abord le contenu de la page à htmlPath, puis d'utiliser 

appWebView!.loadHTMLString()

charger la page. Cela fonctionne quand la page HTML est simple. Mais si le HTML fait référence à quelque chose d'autre, c'est-à-dire un fichier JavaScript également dans le répertoire du document (avec un chemin absolu comme <script src="file:////var/mobile/Containers/Data/Application/762035C9-2BF2-4CDD-B5B1-574A0E2B0728/Documents/xxxxx.js">), le chargement échouera.

Quelqu'un sait-il pourquoi cela se produit et comment résoudre le problème?

Plus d'informations:

  • Version Xcode: 7.3.1
  • Cible de déploiement: 8.1 (j'ai aussi essayé d'utiliser la version 9.3, mais cela n'a pas aidé.)
23
Peter

Ceci est une version simplifiée de ce que j'ai utilisé pour charger des fichiers locaux dans un de mes projets (iOS 10, Swift 3). Je viens de mettre à jour mon code (7.5.2017) après l'avoir testé à nouveau sur iOS 10.3.1 et iPhone 7+, comme demandé par Raghuram et Fox5150 dans les commentaires. 

Je viens de créer un tout nouveau projet et voici la structure de dossiers: enter image description here

Mise à jour 19.04.2018: Ajout d'une nouvelle fonctionnalité permettant de télécharger un fichier .Zip contenant des fichiers HTML, CSS, JS, de le décompresser dans/Documents/(Alamofire + Zip), puis de charger ces fichiers dans la WebView. Vous pouvez également le trouver dans le exemple de projet GitHub . Encore une fois, sentez-vous libre de fourchette et star! :)

Mise à jour 08.02.2018: a finalement ajouté un exemple de projet GitHub }, qui inclut également un fichier JavaScript local. Ne hésitez pas à fork et star! :)

Version 1 avec 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()
    }
}

Version 2 avec 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()
    }
}

Les pièges à surveiller:

  • Assurez-vous que vos fichiers html/js/css locaux sont dans Projet -> Cible -> Phases de construction -> Copier les ressources du bundle
  • Assurez-vous que vos fichiers HTML ne font pas référence à des chemins relatifs, par exemple. css/styles.css car iOS aplatira votre structure de fichier et styles.css sera au même niveau que index.html, écrivez donc <link rel="stylesheet" type="text/css" href="styles.css"> à la place

Étant donné les 2 versions et les pièges, voici mes fichiers html/css du projet:

web/index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    <title>Offline WebKit</title>
    <link rel="stylesheet" type="text/css" href="styles.css">
  </head>
  <body>
    <h1 id="webkit-h1">Offline WebKit!</h1>
  </body>
</html>

web/css/styles.css

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

Si quelqu'un veut un exemple de projet GitHub, dites-le-moi dans la section commentaires et je le téléchargerai.

29
tech4242

Méthode Swift 4

Cette méthode permet à WKWebView de lire correctement votre hiérarchie de répertoires et de sous-répertoires pour les fichiers CSS/JS liés. Vous n'avez PAS besoin de changer votre code HTML, CSS ou JS.

Mis à jour pour Xcode 9.3

Étape 1

Importez le dossier des fichiers Web locaux n’importe où dans votre projet. Assurez-vous que vous:

 Xcode > File > Add Files to "Project"

☑️ Copier les éléments si nécessaire

☑️ Créer des références de dossier} _ (pas "Créer des groupes")

☑️ Ajouter aux cibles

Étape 2

Accédez au contrôleur de vue avec WKWebView et ajoutez le code suivant à la méthode viewDidLoad:

let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "website")!
webView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
webView.load(request)
  • index - le nom du fichier à charger (sans l'extension .html)
  • website - le nom de votre dossier Web (index.html devrait être à la racine de ce répertoire)

Conclusion

Le code général devrait ressembler à ceci:

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 l'un d'entre vous a d'autres questions sur cette méthode ou le code, je ferai de mon mieux pour y répondre. :)

7
Matt Swift

Cette solution m'a aidé à: 

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

Cela fonctionne 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.")
            }
        }
    }
}
0
hkdalex

Cela fonctionne bien avec l'URL du fichier ou l'URL distante, et que le fichier soit dans l'ensemble ou dans les documents:

if url.isFileURL {
    webView.loadFileURL(url, allowingReadAccessTo: url)
} else {
    let request = URLRequest(url: url)
    webView.load(request)
}
0
drewster