56 votes

WKWebView ne parvient pas à charger les images et les CSS en utilisant loadHTMLString(_, baseURL :)

Recommandation d'Apple :

Dans les applications exécutées sous iOS 8 et les versions ultérieures, utilisez la classe WKWebView au lieu d'utiliser UIWebView.

Ainsi, j'ai remplacé mon bon vieux UIWebView avec une nouvelle et brillante WKWebView . Mais ce que je pensais être un exercice facile (il suffisait d'intervertir les classes et de remplacer les méthodes de délégation) s'est avéré être une véritable pagaille.

Le problème

Lorsque je charge une chaîne HTML en utilisant

loadHTMLString(String, baseURL: URL?)

la vue web charge et rend le pur HTML mais il ne charge pas les images ou les fichiers CSS référencés à l'intérieur de la balise htmlString .

Cela arrive uniquement sur un appareil réel ¡!
Dans Simultor, toutes les ressources référencées sont chargées correctement.

Simulator Real Device

Exemple

J'ai défini un simple htmlString dans ma classe de contrôleur de vue :

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
}

L'image est stockée dans le dossier Root Library et son URL est donc la suivante :

let imageURL = libraryURL.appendingPathComponent(imageName)

Maintenant, je charge le htmlString dans la vue web :

webView.loadHTMLString(htmlString, baseURL: libraryURL)

et il ne charge pas l'image même si l'option baseURL est correctement réglé.

Des idées pour une solution

  1. Peut-être WKWebView a un problème avec la résolution des chemins relatifs, donc ma première idée était d'utiliser chemins absolus à l'intérieur de la chaîne HTML.
    Ça ne marche pas.

  2. Deux réponses à un autre poste SO a suggéré que l'utilisation
    loadFileURL(URL, allowingReadAccessTo: URL)
    au lieu de loadHTMLString(...) fonctionne dans iOS 9+.
    Ça marche.

Cependant, je ne peux pas utiliser la solution 2 car mes fichiers HTML sont cryptés et les fichiers décryptés ne doivent pas être stockés sur le disque.

Question

Existe-t-il un moyen de charger des ressources locales telles que des images et des styles à l'aide de la fonction WKWebView 's

loadHTMLString(String, baseURL: URL?)

fonction ? Ou est-ce encore un bug dans iOS 9+ ?

(Je n'arrive pas à croire qu'Apple fournisse et recommande l'utilisation d'une vue web qui ne peut charger aucun contenu web local à partir d'une chaîne HTML).

0 votes

0 votes

0 votes

J'ai le même problème. J'ai essayé avec "loadFileURL(URL, allowingReadAccessTo : URL)". Cela ne fonctionne toujours pas pour moi. Les images ne se chargent toujours pas. Comment avez-vous réussi à le faire fonctionner ?

16voto

Petro Korienev Points 1900

Sans examiner votre projet réel, il est difficile de donner des conseils sûrs à cent pour cent.

Cependant :

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_) - Stack Overflow", 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.
    }
}

Je pense que le point clé ici est baseUrl vous devriez le configurer correctement. Dans mon cas, j'ai utilisé l'url du html sans le dernier composant du chemin - par exemple, le dossier contenant. Cela fonctionne bien sur le dispositif et le simulateur - vérifiez le snapshot du dispositif. J'ai téléchargé l'exemple de projet sur https://github.com/soxjke/WKWebViewTest pour que vous puissiez y jeter un coup d'oeil (j'ai supprimé les informations de signature de code de git)

Device snapshot

Donc, pour résumer - la méthode fonctionne, la fonctionnalité fonctionne, mais vous faites quelque chose de mal avec elle. Pour vous aider à comprendre ce qui ne va pas dans vos solutions, je vais ajouter quelques suggestions : 1. Rappelez-vous que le système de fichiers du simulateur est insensible à la casse Le système de fichiers du périphérique est sensible à la casse . Donc, si vos noms de fichiers en html sont en minuscules, cela ne fonctionnera pas sur l'appareil. 8fFsD.png != 8ffsd.png 2. Rappelez-vous que lorsque vous copiez des ressources, XCode ignore la structure de votre dossier. Donc si votre html a <img src="./img/1.png"> et que votre projet XCOde a une structure de dossier telle que

test.htm

img/

    1.png 
    2.png

Après la construction, il sera aplati, de sorte que test.htm, 1.png et 2.png se trouveront au même niveau.

test.htm
1.png 
2.png

Je suis presque sûr qu'après avoir vérifié ces deux hypothèses, vous arriverez à faire fonctionner cette méthode.

1 votes

Merci de partager l'exemple de projet sur GitHub. Avec cela, j'ai pu faire en sorte que le webview charge les ressources sur mon iPhone. Je n'ai pas encore trouvé ce qui ne va pas dans mon implémentation et pourquoi cela ne fonctionne que dans le simulateur, mais je vais y réfléchir dès que j'en aurai le temps et je posterai mes conclusions dans une autre réponse sur cette page.

0 votes

Heureux que ma réponse vous aide. Comme je l'ai écrit, je vous suggère de vérifier d'abord les noms de fichiers et la casse, puis la structure des dossiers. A 99%, vous trouverez un problème.

1 votes

J'ai résolu mon problème. Merci !

3voto

tech4242 Points 1548

Vous devriez être en mesure d'utiliser des images locales et des fichiers CSS (ainsi que des fichiers JavaScript) avec WKWebViews grâce à la fonction que vous avez déjà trouvée. Je pense que le problème se situe au niveau de votre baseURL variable.

Mise à jour 7.5.2017 :

J'ai complètement mis à jour le code de une autre réponse de SO de la mienne qui était liée à ma réponse ici. J'ai un projet de travail pour loadHTMLString() y .loadFileURL()

1 votes

Avez-vous essayé cela sur un appareil réel ? Parce que c'est à peu près ce que j'ai fait. Le site baseURL est censé être l'emplacement à partir duquel vos chemins relatifs sont résolus, mais le problème ne peut pas vraiment être lié à cela, car j'ai essayé de référencer des chemins absolus dans le HTML également et cela ne fonctionne pas non plus.

0 votes

(Btw : Une fois que vous avez compris les bizarreries tout est très bien. Il ne devrait pas y avoir de bizarreries en premier lieu !)

3voto

Chris Brandsma Points 7225

Personnellement, j'ai dû passer à l'utilisation de XWebView car le comportement de WKWebView ne permet pas le chargement de fichiers locaux. XWebView le contourne en chargeant un serveur web local en arrière-plan et en dirigeant le trafic local à travers lui (XWebView est basé sur WKWebView).

Cela semble un peu exagéré, mais c'est ce que j'ai fini par faire.

0 votes

Merci pour l'information. J'ai lu cette astuce de serveur web dans d'autres articles. Mais j'ai vraiment l'impression que c'est un peu exagéré d'utiliser une bibliothèque externe pour configurer un serveur web local juste pour rendre un peu de HTML de base - une tâche qui est le but principal d'une webview !

3voto

ianyh Points 349

J'ai également expérimenté cette méthode, avec des restrictions similaires, et le problème semble être que les chemins ne sont pas résolus à moins que baseURL fait référence au paquet d'applications. Cela ne fonctionne pas si, par exemple, vous avez quelque chose dans les documents de l'application.

Edit : J'ai déposé un radar pour cela rdar://29130863

0 votes

J'ai exactement le même problème que le rdar. Est-ce que par hasard vous vous souvenez de ce que vous avez fini par faire ? :)

2voto

moliveira Points 139

Vous pouvez coder les images en base64... Je sais que ça marche. Mais je ne suis pas sûr que cela convienne à votre cas d'utilisation.

C'est drôle, je viens de rencontrer ce problème en faisant l'inverse - en passant de fichiers codés en base64 à des fichiers image.

0 votes

Cela semble être une solution intelligente ! Je vais l'essayer. Cependant, cela ressemble vraiment à un piratage sale dans mon cas, car je vais devoir analyser le HTML, trouver toutes les URL des images, les encoder en données base64 et remplacer l'URL par ces données.

0 votes

Oui, je peux voir ça. Dans mon cas, j'ai déjà l'image que je veux mettre dans le html, donc c'était un peu plus propre.

0 votes

J'ai essayé de coder les images en base64 et cela ne fonctionne toujours pas. github.com/starkindustries/Print2PDFTest

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X