WKWebView如何处理blob URL并实现文件下载?低版本iOS兼容问题求解
WKWebView 低版本(iOS < 14.5)Blob 链接下载解决方案
你遇到的XHR不触发onload的核心原因是两个:
- 原生拼接JS字符串时容易出现特殊字符转义问题,导致JS执行异常
- WKWebView对原生注入的XHR请求访问Blob URL有上下文权限限制,低版本iOS上触发了安全拦截
前置准备
首先确保你初始化WKWebView时已经正确注册了JS交互回调Handler:
let config = WKWebViewConfiguration() let userContent = WKUserContentController() // 注册和JS侧对应的回调名称,要和JS里postMessage的第一个参数一致 userContent.add(self, name: "callback") config.userContentController = userContent webView = WKWebView(frame: .zero, configuration: config)
同时你需要实现WKScriptMessageHandler协议接收JS返回的base64数据:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.name == "callback", let base64Str = message.body as? String else { return } // 处理base64数据转存文件 handleBlobBase64(base64Str, fileName: "你要保存的文件名") }
修正Blob下载逻辑
不要直接拼接JS字符串传Blob地址,改用参数注入或者兼容性更好的fetch方案替换XHR,低版本iOS对fetch处理Blob的兼容性更好:
private func downloadBlobFile(blobUrl: String, fileName: String, mimeType: String) { // 注意不要手动加javascript:前缀,evaluateJavaScript会自动处理 let jsStr = """ fetch('\(blobUrl)') .then(res => res.blob()) .then(blob => { const reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = () => { window.webkit.messageHandlers.callback.postMessage(reader.result); }; }) .catch(err => console.log('下载失败', err)); """ webView.evaluateJavaScript(jsStr) { _, error in if let error = error { print("JS执行失败: \(error)") } } }
如果你的Blob链接里包含单引号等特殊字符,需要先对blobUrl做转义处理,避免JS语法错误
实现base64转存本地文件逻辑
private func handleBlobBase64(_ base64Str: String, fileName: String) { // 去掉base64前缀 比如data:application/pdf;base64, guard let dataRange = base64Str.range(of: "base64,") else { return } let pureBase64 = String(base64Str[dataRange.upperBound...]) guard let fileData = Data(base64Encoded: pureBase64) else { return } let tempDir = NSTemporaryDirectory() let destinationPath = (tempDir as NSString).appendingPathComponent(fileName) let destinationURL = URL(fileURLWithPath: destinationPath) do { try fileData.write(to: destinationURL) openDownloadFile(destinationURL) } catch { print("文件保存失败: \(error)") } }
原有代码的小问题修正
你现有downloadData方法里存在变量名错误:
// 原来的错误写法 let task = session.downloadTask(with: downloadURL) // 修正为传入的参数url let task = session.downloadTask(with: url)
踩坑说明
- 去掉blob:前缀用URLSession下载无效:Blob URL是当前网页上下文的临时内存地址,仅在WKWebView的JS运行环境中有效,原生网络层无法访问
- LSApplicationQueriesSchemes添加blob配置无效:该配置仅用于控制
openURL跳转的scheme白名单,和Blob资源访问逻辑无关
内容的提问来源于stack exchange,提问作者ruslan
相关产品推荐
相关产品推荐

