Android WebView中下载BLOB格式PDF文件的问题
WebView 下载 Blob URL PDF 解决方案
Android 端实现步骤
- 注入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); } });
- 注册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 端实现步骤
- 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
相关产品推荐
相关产品推荐

