Android WebView字符编码异常?Blob(PDF)加载404问题求助
关于Android WebView处理Blob PDF下载的问题解答
我之前刚好踩过类似的Blob PDF下载坑,你的猜测确实是可能的原因之一,但还有更核心的问题需要注意。
首先说Cookie的问题:Blob URL是浏览器在当前页面会话中临时生成的,它和WebView当前的Cookie、会话状态完全绑定。如果你直接把转义后的https:// URL拿去发起独立请求(比如用OkHttp或者HttpURLConnection),这个请求不会携带WebView上下文里的Cookie,服务器会因为权限校验失败返回404或者未授权错误——这部分你的猜测是对的。
但还有一个更关键的点:很多时候前端生成的Blob URL对应的资源,根本不存在于服务器上。它可能是前端通过接口拿到二进制数据后,在本地内存中生成的Blob对象,对应的URL只是浏览器用来指向内存数据的临时标识。这种情况下,你哪怕带上Cookie去请求转义后的URL,服务器也找不到这个资源,一样会返回404。
我常用的解决思路
不要尝试去解析或请求Blob URL,而是通过JavascriptInterface让WebView在前端上下文里把Blob内容直接传递给Native端:
- Native端定义JavascriptInterface
public class PdfHandler { @JavascriptInterface public void receivePdfData(String base64Content, String fileName) { // 把Base64字符串转成字节数组 byte[] pdfBytes = Base64.decode(base64Content, Base64.DEFAULT); // 后续执行保存文件的逻辑,比如写入本地存储 savePdfToLocal(pdfBytes, fileName); } private void savePdfToLocal(byte[] data, String fileName) { // 实现文件保存的具体代码,这里省略 } }
- 给WebView注入JS拦截Blob下载事件
在WebView加载完成后,注入一段JS代码,拦截所有Blob开头的下载请求,把Blob转成Base64后传给Native:
webView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 注入JS代码 String js = "document.addEventListener('click', function(e) {" + " if (e.target.tagName === 'A' && e.target.href.startsWith('blob:')) {" + " e.preventDefault();" + " fetch(e.target.href)" + " .then(res => res.blob())" + " .then(blob => {" + " const reader = new FileReader();" + " reader.onload = function() {" + " const base64 = reader.result.split(',')[1];" + " window.PdfHandler.receivePdfData(base64, 'download.pdf');" + " };" + " reader.readAsDataURL(blob);" + " });" + " }" + "});"; webView.evaluateJavascript(js, null); } }); // 绑定JavascriptInterface webView.addJavascriptInterface(new PdfHandler(), "PdfHandler"); webView.getSettings().setJavaScriptEnabled(true);
- 额外注意事项
- 确保WebView允许相关权限:
setAllowFileAccess(true)、setAllowFileAccessFromFileURLs(true); - 如果前端是通过其他方式触发下载(比如JS调用
window.open),需要调整JS拦截的逻辑,监听对应的事件; - 对于大体积PDF,Base64可能会有性能问题,也可以考虑用分块传递的方式,但大部分场景下Base64足够用。
内容的提问来源于stack exchange,提问作者Daniel V
相关产品推荐
相关产品推荐

