WKWebView does load resources from local document folder WKWebView does load resources from local document folder swift swift

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

Update 19.04.2018: Added a new feature to download a .zip with HTML, CSS, JS files, unzip it in /Documents/ (Alamofire + Zip) and then load those files into the webView. You can find it in the GitHub sample project as well. Again, feel free to fork & star! :)

Update 08.02.2018: finally added a GitHub sample project, which also includes a local JavaScript file. Feel free to fork & star! :)

Version 1 with webView.loadFileURL()

ViewController.swift

import UIKitimport WebKitclass 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    }}

Version 2 with webView.loadHTMLString()

ViewController.swift

import UIKitimport WebKitclass 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    }}

Gotchas 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 gotchas 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.


Swift 4 Method

This method allows WKWebView to properly read your hierarchy of directories and sub-directories for linked CSS/JS files. You do NOT need to change your HTML, CSS or JS code.

Updated for Xcode 9.3

Step 1

Import the folder of local web files anywhere into your project. Make sure that you:

Xcode > File > Add Files to "Project"

☑️ Copy items if needed

☑️ Create folder references (not "Create groups")

☑️ Add to targets

Step 2

Go to the View Controller with the WKWebView and add the following code to the viewDidLoad method:

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 – the name of the file to load (without the .html extension)
  • website – the name of your web folder (index.html should be at the root of this directory)

Conclusion

The overall code should look something like this:

import UIKitimport WebKitclass 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)    }}

If any of you have further questions about this method or the code, I'll do my best to answer. :)


This solution helped me:

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