Search code examples
iosswiftuiwebview

Load Internal Assets from HTML File inside UIWebView


In my app built in Xcode 8.2 I have a controller with the web view where web view loads an internal HTML file like this:

    let htmlFile = Bundle.main.path(forResource: "web/place-info", ofType: "html")
    var htmlString = try? String(contentsOfFile: htmlFile!, encoding: String.Encoding.utf8)
    self.webView.loadHTMLString(htmlString!, baseURL: nil)

Then I want to include some additional JavaScript and CSS into that HTML file but the file fails to load any. The including path seems to be either wrong or blocked.

<link rel="stylesheet" href="web/font-awesome/css/font-awesome.min.css">

What is more strange is that this image will never load inside place-info.html BODY tag:

        <img src="ic-user-profile.png" />
        <img src="/ic-user-profile.png" />
        <img src="img/ic-user-profile.png" />
        <img src="/img/ic-user-profile.png" />
        <img src="web/img/ic-user-profile.png" />
        <img src="/web/img/ic-user-profile.png" />
        <img src="Project-Name/web/img/ic-user-profile.png" />
        <img src="/Project-Name/web/img/ic-user-profile.png" />
        <img src="Project-Name/Project-Name/web/img/ic-user-profile.png" />
        <img src="/Project-Name/Project-Name/web/img/ic-user-profile.png" />

Am I missing some special setting in Xcode 8.2? Note that in settings I already have App Transport Security Settings to be Allow Arbitrary Loads = YES


Solution

  • The culprit is that you pass nil as baseURL and only give the web view a string to load. It can't possibly know the location from where to load files referenced by relative links.

    So just pass the folder where place-info.html is located as base URL:

    let baseURL = Bundle.main.url(forResource: "web", withExtension: nil)!
    let contentURL = baseURL.appendingPathComponent("place-info.html")
    let htmlString = try? String(contentsOf: contentURL, encoding: String.Encoding.utf8)
    self.webView.loadHTMLString(htmlString!, baseURL: baseURL)
    

    Then, relative links like

    • <img src="ic-user-profile.png" />
    • <link rel="stylesheet" href="font-awesome/css/font-awesome.min.css">

    will load the resources from locations relative to your web folder. Note that I removed web/ from your stylesheet href, assuming that the web folder contains font-awesome/css/font-awesome.min.css:

    web/
     |- place-info.html
     |- ic-user-profile.png
     |- font-awesome/
          |- css/
              |- font-awesome.min.css
    

    Adding to Jacob Boyd's comment, please also note the UIWebView API Reference states

    In apps that run in iOS 8 and later, use the WKWeb​View class instead of using UIWeb​View.

    Which is further emphasized by WKWebView's API Reference:

    Important
    Starting in iOS 8.0 and OS X 10.10, use WKWebView to add web content to your app. Do not use UIWebView or WebView.