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:
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:
☑️ 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. :)