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

Android WebView中下载BLOB格式PDF文件的问题

WebView 下载 Blob URL PDF 解决方案

Android 端实现步骤

  1. 注入JavaScript 拦截 Blob 请求
    在WebView页面加载完成后,注入脚本监听PDF下载链接点击,将Blob转为Base64数据传递给原生层:
webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        String jsScript = "document.addEventListener('click', function(e) {" +
                    "  let target = e.target;" +
                    "  if(target.tagName === 'A' && target.href.startsWith('blob:')) {" +
                    "    e.preventDefault();" +
                    "    fetch(target.href)" +
                    "      .then(res => res.blob())" +
                    "      .then(blob => {" +
                    "        let reader = new FileReader();" +
                    "        reader.onloadend = function() {" +
                    "          let base64Str = reader.result.split(',')[1];" +
                    "          window.android.downloadPDF(base64Str, 'download.pdf');" +
                    "        };" +
                    "        reader.readAsDataURL(blob);" +
                    "      });" +
                    "  }" +
                    "});";
        webView.evaluateJavascript(jsScript, null);
    }
});
  1. 注册JS交互接口处理下载
    定义原生类接收JS传递的Base64数据,解码后写入文件并触发系统下载:
public class JsDownloadBridge {
    @JavascriptInterface
    public void downloadPDF(String base64Data, String fileName) {
        byte[] pdfBytes = Base64.decode(base64Data, Base64.DEFAULT);
        File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        File pdfFile = new File(downloadDir, fileName);
        
        try (FileOutputStream fos = new FileOutputStream(pdfFile)) {
            fos.write(pdfBytes);
            MediaScannerConnection.scanFile(webView.getContext(), new String[]{pdfFile.getAbsolutePath()}, null, null);
            Toast.makeText(webView.getContext(), "PDF已保存至下载目录", Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(webView.getContext(), "下载失败", Toast.LENGTH_SHORT).show();
        }
    }
}

给WebView绑定该接口:

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JsDownloadBridge(), "android");

iOS 端实现步骤

  1. WKWebView 注入脚本并监听消息
    通过WKScriptMessageHandler接收JS传递的Blob数据:
class PDFDownloadVC: UIViewController, WKScriptMessageHandler, WKNavigationDelegate {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = WKWebViewConfiguration()
        config.userContentController.add(self, name: "downloadPDF")
        
        webView = WKWebView(frame: view.bounds, configuration: config)
        webView.navigationDelegate = self
        view.addSubview(webView)
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        let jsScript = """
        document.addEventListener('click', function(e) {
          let target = e.target;
          if(target.tagName === 'A' && target.href.startsWith('blob:')) {
            e.preventDefault();
            fetch(target.href)
              .then(res => res.blob())
              .then(blob => {
                let reader = new FileReader();
                reader.onloadend = function() {
                  let base64Str = reader.result.split(',')[1];
                  window.webkit.messageHandlers.downloadPDF.postMessage({data: base64Str, name: 'download.pdf'});
                };
                reader.readAsDataURL(blob);
              });
          }
        });
        """
        webView.evaluateJavaScript(jsScript, completionHandler: nil)
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard let dataDict = message.body as? [String: String],
              let base64Str = dataDict["data"],
              let fileName = dataDict["name"],
              let pdfData = Data(base64Encoded: base64Str) else { return }
        
        let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let fileURL = docDir.appendingPathComponent(fileName)
        
        do {
            try pdfData.write(to: fileURL)
            let alert = UIAlertController(title: "下载完成", message: "PDF已保存至文件目录", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default))
            present(alert, animated: true)
        } catch {
            print("保存失败:\(error.localizedDescription)")
        }
    }
}

关键注意事项

  • 确保WebView开启JavaScript支持,Android需手动设置setJavaScriptEnabled(true)
  • Android 10+需适配Scoped Storage,避免直接写入外部存储引发权限问题
  • 大体积Blob转Base64可能存在性能损耗,可改用ArrayBuffer直接传递(需额外处理JS与原生的数据交互逻辑)

内容的提问来源于stack exchange,提问作者Hbkares

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 05:15:45