最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - WKWebView xmlhttprequest with file url - Stack Overflow

programmeradmin1浏览0评论

I am migrating from UIWebView to WKWebView with my local HTMLs in the app documents folder. I can load the index page with all css and js files, but every ajax call (xmlhttprequest) fails because of allowed-access-origin.

I don´t want to use a webserver in my application, because I think it would be oversized. How can I make it possible? The app is a simple HTML5 application for an in house app. The device can´t get online or anything so security could be disabled completly.

I am migrating from UIWebView to WKWebView with my local HTMLs in the app documents folder. I can load the index page with all css and js files, but every ajax call (xmlhttprequest) fails because of allowed-access-origin.

I don´t want to use a webserver in my application, because I think it would be oversized. How can I make it possible? The app is a simple HTML5 application for an in house app. The device can´t get online or anything so security could be disabled completly.

Share Improve this question asked Feb 22, 2016 at 13:21 AlteGurkeAlteGurke 5936 silver badges20 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 9

This solved my problem:

let config = WKWebViewConfiguration()
config.userContentController = contentController
config.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self
webView.navigationDelegate = self
view = webView

For those who came though SO to find this topic:

This isn't official to turn off the security in WKWebView, but we could use the private API to allow this just like this guy did for the Cordova project: cordova-plugin-wkwebviewxhrfix

The clue is to create the configuration for the WebView and set the allowFileAccessFromFileURLs property.

WKWebViewConfiguration* configuration = originalImpSend(_self, selector, settings);

// allow access to file api
@try {
    [configuration.preferences setValue:@TRUE forKey:@"allowFileAccessFromFileURLs"];
}
@catch (NSException *exception) {}

@try {
    [configuration setValue:@TRUE forKey:@"allowUniversalAccessFromFileURLs"];
}
@catch (NSException *exception) {}

return configuration;

But as I mentioned this is the private API and it could be a reason to reject your application in Apple's App Review. If you want to publish your app in App Store, please consider to run some lightweight HTTP server instead of violate overall security of the web view. Example: GCDWebServer.

So the accepted was not working for me when I first tried it (I was doing it wrong at the time) and the bug about (https://bugs.webkit.org/show_bug.cgi?id=154916) it strongly recommends against doing it. My solution was to implement a custom url scheme and use that to load all files. Looks like this.

First creating the WKWebView to which the url scheme is attached (you must create the WKWebView yourself, it can't be created on a storyboard).

override func viewDidLoad() {

    let configuration = WKWebViewConfiguration()
    configuration.setURLSchemeHandler(PrayerAssetHandler(), forURLScheme: "x-file")

    webview = WKWebView(frame: webContentView.bounds, configuration: configuration)
    self.webContentView.addSubview(webview!)
    webview?.autoresizingMask = webContentView.autoresizingMask
    webview!.navigationDelegate = self

    super.viewDidLoad()
}

Then implement the handler.

import Foundation
import WebKit
import MobileCoreServices

class PrayerAssetHandler: NSObject, WKURLSchemeHandler {

    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        let url = urlSchemeTask.request.url!

        let pathArr = url.path.components(separatedBy: ".")
        let forResource: String = pathArr[0]
        let ofType: String? = pathArr.count > 1 ? pathArr[1] : nil

        let bundlePath = Bundle.main.path(forResource: "data_sub_folder" + forResource, ofType: ofType)

        let fileExtension: CFString = ofType! as CFString
        guard
            let extUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
                                fileExtension, nil)?.takeUnretainedValue()
        else { return }

        guard
            let mimeUTI: NSString = UTTypeCopyPreferredTagWithClass(extUTI,
                                kUTTagClassMIMEType)?.takeRetainedValue()
        else { return }

        let mimeType: String = mimeUTI as String

        do {
            let data: Data = try NSData(contentsOfFile: bundlePath!) as Data

            //Create a NSURLResponse with the correct mimetype.
            let urlResponse = URLResponse(url: url, mimeType: mimeType,
                                          expectedContentLength: data.count, textEncodingName: "utf8")
            urlSchemeTask.didReceive(urlResponse)
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()
        }  catch _ as NSError {
            return
        }

    }

    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
    }
}

Setting value in preferences is not working in Swift 5. Set in 'WKWebViewConfiguration' as shown below.

// Configuration
let webConfiguration = WKWebViewConfiguration()
webConfiguration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
webConfiguration.setValue(true, forKey: "allowUniversalAccessFromFileURLs")

// Web View
let webView = WKWebView(frame: webviewContainer.frame, configuration: webConfiguration)
发布评论

评论列表(0)

  1. 暂无评论