Wkwebview Does Load Resources from Local Document Folder

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:Sample Image

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

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

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 instead

Given the 2 versions and the gotchas here are my html/css files from the project:

web/index.html





Offline WebKit



Offline WebKit!



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.

Load local web files & resources in WKWebView

Updated for Swift 4, Xcode 9.3


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

Solution (Quick)

  1. Add the web folder to your project (File > Add Files to Project)

    • Copy items if needed
    • Create folder references *
    • Add to targets (that are applicable)
  2. Add the following code to the viewDidLoad and personalize it to your needs:

    let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "website")!
    webView.loadFileURL(url, allowingReadAccessTo: url)
    let request = URLRequest(url: url)
    webView.load(request)

Solution (In-Depth)

Step 1

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

Xcode  rel= 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 UIKit
import WebKit

class 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!

WKWebView cannot load local resource in HTML

Add all the HTML directories & files in your project.

let webView = WKWebView()
if let htmlPath = Bundle.main.path(forResource: "directory/index", ofType: "html") {
let htmlUrl = URL(fileURLWithPath: htmlPath, isDirectory: false)
webView.loadFileURL(htmlUrl, allowingReadAccessTo: htmlUrl)
view = webView
}

Sample Image

WKWebView load files from both Bundle and Document directory

I finally end up as EDIT 1 and @ngbaanh suggested:

  • on viewDidLoad:

    let filemgr = FileManager.default
    docURL = filemgr.urls(for: .documentDirectory, in: .userDomainMask)[0]
    destPath = docURL.path+"/www/"
    sourcePath = Bundle.main.resourceURL!.appendingPathComponent("Web_Assets").path

    //COPY Web_Assets content from Bundle to Documents/www
    do {
    try filemgr.removeItem(atPath: destPath)
    } catch {
    print("Error: \(error.localizedDescription)")
    }
    do {
    try filemgr.copyItem(atPath: sourcePath, toPath: destPath)
    } catch {
    print("Error: \(error.localizedDescription)")
    }

    // Configure Webview
    webView.navigationDelegate = self
    webView.configuration.userContentController.add(self, name: "teleco")
    do {
    let baseURL = try filemgr.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
    let fileURL = baseURL.appendingPathComponent("www/index.html")
    self.loadFileURL(fileURL, allowingReadAccessTo: baseURL)
    } catch {
    print(error)
    }

This way my baseURL is Documents/www/
So in my index.html i can include ressources like style.css

AND i can also access files in Documents/ by using relative path like ../video.mp4

So index.html and style.css are distributed via the Bundle, copied to Documents at runtime, which allows me to access Documents files too.

A bit twisted, but works great.

Downside: it exposes Web_assets files in user accessible Documents folder.
But they can't be altered since they are replaced on App start.

WKWebView:Load contents from documents folder in iOS

My requirement was to load/ change a resource in Index.html from documents or caches folder at run time using java script. (I am not at all hardcoding the paths and I am of-course using file manager). While doing that I was unable to access resources using file:// protocol. Today a I tried a sample app to demonstrate my problem and all of a sudden it starts working :). Now I need to visit my main project and see what is going wrong.

In this sample project I am trying to change the src of an image at run time by passing a path from the caches folder.

WKWebViewAccessDocuments

LoadFileUrl and LoadHtmlString not loading local document resources

You can obtain the doc dir via NSFileManager.DefaultManager.GetUrl.

Example loading "WebSite" from App's document directory

var docsDir = NSFileManager.DefaultManager.GetUrl(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User, null, true, out var error);
var data = NSUrl.FromFilename(Path.Combine(docsDir.Path, "WebSite", "index.html"));
var content = NSUrl.FromFilename(Path.Combine(docsDir.Path, "WebSite"));
webView.LoadFileUrl(data, content);

Example loading "WebSite" from bundled resources:

var bundlePath = NSBundle.MainBundle.BundlePath;
var data = NSUrl.FromFilename(Path.Combine(bundlePath, "WebSite", "index.html"));
var content = NSUrl.FromFilename(Path.Combine(bundlePath, "WebSite"));
webView.LoadFileUrl(data, content);

Using an downloaded Azure sample website

Note: Downloaded to a WebSite subdir within NSSearchPathDirectory.DocumentDirectory

├── css
│   └── site.css
├── fonts
│   └── segoeuil.ttf
├── img
│   ├── cloneWhite.svg
│   ├── deployWhite.svg
│   ├── lightbulbWhite.svg
│   ├── stackWhite.svg
│   ├── successCloudNew.svg
│   └── tweetThis.svg
└── index.html

Local Output:

Sample Image

Swift: Unable to load local images in WKWebView

The problem is that this statement is wrong:

My folder structure:

- web
-- images
-- test.png
-- index.html

That may be what the Project navigator looks like, but those yellow things in the Project navigator ("web", "images") are not folders. They are just organizational devices for the Project navigator itself (groups), to help you find your stuff. In the built app, your resources are being loaded flat into the app bundle, so that test.png and index.html are at the same level together, namely, the top level of the bundle.

If what you really wanted was in fact a "web" folder with that structure inside your app bundle, then you needed this to be a folder reference, which is a very different thing.



Related Topics



Leave a reply



Submit