我需要在WKWebView中实现文件下载。
我的示例实现:
@available(iOS 14.5, *)
func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
download.delegate = self
}
@available(iOS 14.5, *)
func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
download.delegate = self
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if let mimeType = navigationResponse.response.mimeType {
if let url = navigationResponse.response.url {
if #available(iOS 14.5, *) {
decisionHandler(.download)
} else {
let ext = getExtension(mimeType)
let fileName = "file." + ext;
downloadData(fromURL: url, fileName: fileName) { success, destinationURL in
if success, let destinationURL = destinationURL {
self.openDownloadFile(destinationURL)
}
}
decisionHandler(.cancel)
}
return
}
}
decisionHandler(.allow)
}
private func downloadData(fromURL url: URL,
fileName: String,
completion: @escaping (Bool, URL?) -> Void) {
webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
let session = URLSession.shared
session.configuration.httpCookieStorage?.setCookies(cookies, for: url, mainDocumentURL: nil)
let task = session.downloadTask(with: downloadURL) { localURL, _, error in
if let localURL = localURL {
let destinationURL = self.moveDownloadedFile(url: localURL, fileName: fileName)
completion(true, destinationURL)
} else {
completion(false, nil)
}
}
task.resume()
}
}
private func moveDownloadedFile(url: URL, fileName: String) -> URL {
let tempDir = NSTemporaryDirectory()
let destinationPath = tempDir + fileName
let destinationURL = URL(fileURLWithPath: destinationPath)
try? FileManager.default.removeItem(at: destinationURL)
try? FileManager.default.moveItem(at: url, to: destinationURL)
return destinationURL
}
private func openDownloadFile(_ fileUrl: URL) {
DispatchQueue.main.async {
let controller = UIActivityViewController(activityItems: [fileUrl], applicationActivities: nil)
controller.popoverPresentationController?.sourceView = self.view
controller.popoverPresentationController?.sourceRect = self.view.frame
controller.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
self.present(controller, animated: true, completion: nil)
}
}
它适用于iOS >= 14.5以及响应为文件的情况。但是当url为blob(例如"blob:http://example.com/bd0ae6c8-796c-488e-b691-cee86fa72f04"
)时,它在iOS < 14.5上无法正常工作。
返回不支持的URL错误。
我尝试像在Android中一样处理和下载blob url (Android示例):
private func downloadBlobFile(blobUrl: String, fileName: String, mimeType: String) {
webView.evaluateJavaScript("javascript: var xhr = new XMLHttpRequest();" +
"xhr.open('GET', '" + blobUrl + "', true);" +
"xhr.setRequestHeader('Content-type','" + mimeType + "');" +
"xhr.responseType = 'blob';" +
"xhr.onload = function(e) {" +
" if (this.status == 200) {" +
" var blob = this.response;" +
" var reader = new FileReader();" +
" reader.readAsDataURL(blob);" +
" reader.onloadend = function() {" +
" base64data = reader.result;" +
" window.webkit.messageHandlers.callback.postMessage(base64data);" +
" }" +
" }" +
"};" +
"xhr.send();")
}
这段代码在Android上运行良好,但是在iOS上并没有调用xhr.onload
,而是用空的responseText
调用了xhr.onerror
。
我还尝试去掉blob url中的"blob:"。
"blob:http://example.com/bd0ae6c8-796c-488e-b691-cee86fa72f04"
-> "http://example.com/bd0ae6c8-796c-488e-b691-cee86fa72f04"
,然后使用NSURLSession下载。 但是它给我下载了一个损坏的文件。