WKWebView xmlhttprequest 与文件 url

WKWebView xmlhttprequest with file url

我正在从应用程序文档文件夹中的本地 HTML 从 UIWebView 迁移到 WKWebView。 我可以加载包含所有 css 和 js 文件的索引页面,但是每个 ajax 调用 (xmlhttprequest) 都会因为 allowed-access-origin.

而失败

我不想在我的应用程序中使用网络服务器,因为我认为它会过大。我怎样才能让它成为可能?该应用程序是内部应用程序的简单 HTML5 应用程序。设备无法上网或其他任何东西,因此安全性可能会被完全禁用。

对于那些通过 SO 来查找此主题的人:

这不是正式关闭 WKWebView 中的安全性,但我们可以使用私有 API 允许这样做,就像这个人为 Cordova 项目所做的那样:cordova-plugin-wkwebviewxhrfix

线索是为 WebView 创建配置并设置 allowFileAccessFromFileURLs 属性。

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;

但正如我提到的,这是 私人 API,这可能是 拒绝您在 Apple 的申请 的原因应用审查。如果您想在 App Store 中发布您的应用程序,请考虑 运行 一些轻量级的 HTTP 服务器,而不是违反网络视图的整体安全性。示例:GCDWebServer.

这解决了我的问题:

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

所以当我第一次尝试时,accepted 对我不起作用(当时我做错了)并且关于 (https://bugs.webkit.org/show_bug.cgi?id=154916) 的错误强烈建议不要这样做。我的解决方案是实施自定义 url 方案并使用它来加载所有文件。看起来像这样。

首先创建绑定url方案的WKWebView(必须自己创建WKWebView,不能在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()
}

然后实现处理程序。

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

首选项中的设置值在 Swift 中不起作用 5. 在'WKWebViewConfiguration'中设置如下图。

// 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)