maigre
maigre

Reputation: 153

WKWebView load files from both Bundle and Document directory

I am running a webapp using WKWebView which load content and assets (html, js, img, css...) from a Bundle directory called Web_Assets.

I proceed like this to load index.html, and set Web_assets as baseURL:

if let filePath = Bundle.main.path(forResource:"index", ofType:"html", inDirectory: "Web_Assets") { 
    let html = try String(contentsOfFile: filePath, encoding: .utf8)
    webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL?.appendingPathComponent("Web_Assets"))
}

This works perfectly: index.html is loaded and Web_Assets serve as base path for other ressources without any problem. I could also use the loadFileURL method which is equivalent (to my understanding).

BUT, now i'd like to use other ressources (video in my case) inside my WKWebView from the Document directory which is static and manageable via iTunes File Sharing, while of course keeping the present architecture as it is (Web assets inside Bundle directory).

For example my page index.html would load his style.css and other assets from Web_Assets and display an HTML5 video located in Document

Is it possible to do this ?

Ideas (which i don't know how to achieve):

  1. Symlink of Document in Web_assets ?
  2. Different baseURL for different file types in WKWebView ? (route all requests to Web_Assets except for mp4 files requests which are routed to Document)

Thanks for your help !

EDIT 1: Idea 1 is not possible since Bundle directories are read-only. Document can't be symlinked in Web_assets. I can't manage to symlink Web_assets into Document either (weird error). So i decided for now to copy Web_assets inside Document on each boot, so my Document folder can act as baseURL with my videos and web assets altogether.

It's a bit dirty since all my web assets are now visible in my Document folder (but not modifiable since the folder is erased and copied from Bundle uppon App restart)

Upvotes: 6

Views: 3265

Answers (1)

maigre
maigre

Reputation: 153

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.

Upvotes: 4

Related Questions