You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WKWebView如何处理blob URL并实现文件下载?低版本iOS兼容问题求解

WKWebView 低版本(iOS < 14.5)Blob 链接下载解决方案

你遇到的XHR不触发onload的核心原因是两个:

  1. 原生拼接JS字符串时容易出现特殊字符转义问题,导致JS执行异常
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 04:42:03