WKWebView does load resources from local document folder

In my swift iOS app, i want to download some dynamic html pages from a remote server, save in the document directory, and display those pages from document directory.

I was using this to load the page

  • UIButton not showing highlight on tap in iOS7
  • JSON parsing on iPhone SDK
  • Swipe to go back only works on edge of screen?
  • How to display superscript % character as string in UIlabel?
  • Xcode 6 Beta: No such module 'Cocoa'
  • Problems with window.history using JQuery/Javascript on Cordova app in IOS9
  • var appWebView:WKWebView?
    ...
    appWebView!.loadRequest(NSURLRequest(URL: NSURL(fileURLWithPath: htmlPath)))
    

    Everything works on emulator, but when i moved to real phones, it just showed a blank page. I then connect to the app using safari, and found it complained about “Failed to load resource”.

    I then tried to first read the content of page at htmlPath, then use

    appWebView!.loadHTMLString()
    

    to load the page. It works when the html page is simple. But if the html reference something else, i.e. a javascript also in document directory (with a absolute path like <script src="file:////var/mobile/Containers/Data/Application/762035C9-2BF2-4CDD-B5B1-574A0E2B0728/Documents/xxxxx.js">), it will fail to load.

    Anyone know why this happens, and How to resolve this?

    More info:

    • XCode version: 7.3.1
    • Deployment Target: 8.1 (I tried to use 9.3 too,
      didn’t help)

    2 Solutions Collect From Internet About “WKWebView does load resources from local document folder”

    This is a simplified version of what I have used to load local files in a project of mine (iOS 10, Swift 3). I have just updated my code (7.5.2017) after testing it out again on iOS 10.3.1 and iPhone 7+ as requested by Raghuram and Fox5150 in the comments.

    I just created a completely new project and this is the folder structure:enter image description here

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

    Gotcha’s to look out for:

    • Make sure that your local html/js/css files are in Project -> Target -> Build Phases -> Copy Bundle Resources
    • Make sure that your html files don’t reference relative paths e.g. css/styles.css because iOS will flatten your file structure and styles.css will be on the same level as index.html so write <link rel="stylesheet" type="text/css" href="styles.css"> instead

    Given the 2 versions and the gotcha’s here are my html/css files from the project:

    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;
    }
    

    If somebody wants a GitHub sample project, tell me in the comments section and I’ll upload it.

    This works well (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.")
                }
            }
        }
    }