Android WebView中Blob URL文件下载崩溃问题求助
解决Android WebView中Blob URL下载崩溃的问题
问题根源
DownloadManager仅支持HTTP/HTTPS协议的URI,而Blob URL(如blob:https://www.test.com/c14bc5a8-b13c)是浏览器内部生成的本地内存资源标识,并非远程HTTP资源,因此会触发IllegalArgumentException异常。
解决方案:通过JavaScript接口处理Blob下载
核心思路是利用WebView的JavaScript接口,将Blob资源转为Base64格式传递到Java层,再本地写入文件。
步骤1:定义JavaScript交互接口类
public class WebAppInterface { private final Context mContext; private String mTargetFileName; public WebAppInterface(Context context) { mContext = context; } @JavascriptInterface public void receiveBlobData(String base64Data, String fileName) { mTargetFileName = fileName; // 解码Base64数据 byte[] fileBytes = Base64.decode(base64Data, Base64.DEFAULT); saveFileToLocal(fileBytes); } private void saveFileToLocal(byte[] data) { // 配置下载目录 File downloadDir = Environment.getExternalPublicDirectory(Environment.DIRECTORY_DOWNLOADS); File outputFile = new File(downloadDir, mTargetFileName); try (FileOutputStream fos = new FileOutputStream(outputFile)) { fos.write(data); // 通知媒体扫描器更新文件索引 MediaScannerConnection.scanFile(mContext, new String[]{outputFile.getAbsolutePath()}, null, null); Toast.makeText(mContext, "下载完成", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(mContext, "下载失败", Toast.LENGTH_SHORT).show(); } } }
步骤2:修改WebView配置与DownloadListener
// 启用JavaScript(必须) webView.getSettings().setJavaScriptEnabled(true); // 注册JavaScript交互接口 webView.addJavascriptInterface(new WebAppInterface(this), "AndroidBlobDownloader"); webView.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { if (url.startsWith("blob:")) { // 处理Blob URL:注入JS代码获取Blob的Base64数据 String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); String fetchBlobJs = "fetch('" + url + "')" + ".then(res => res.blob())" + ".then(blob => {" + " const reader = new FileReader();" + " reader.onloadend = () => {" + " const base64 = reader.result.split(',')[1];" + " AndroidBlobDownloader.receiveBlobData(base64, '" + fileName + "');" + " };" + " reader.readAsDataURL(blob);" + "});"; // 在主线程执行JS代码 webView.post(() -> webView.evaluateJavascript(fetchBlobJs, null)); } else { // 原有HTTP/HTTPS URL的下载逻辑保持不变 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setMimeType(mimetype); String cookie = CookieManager.getInstance().getCookie(url); request.addRequestHeader("cookie", cookie); request.addRequestHeader("User-Agent", userAgent); request.setDescription("Downloading..."); String outputFileName = URLUtil.guessFileName(url, contentDisposition, mimetype); request.setTitle(outputFileName); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, outputFileName); DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); manager.enqueue(request); } } });
步骤3:权限配置
- 在
AndroidManifest.xml中添加存储权限(Android 10及以上可适配Scoped Storage替代):
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Android 6.0+需动态申请存储权限,确保写入文件时权限正常。
注意事项
- 确保WebView已启用JavaScript,否则无法执行Blob转Base64的逻辑。
- 针对Android 11+的Scoped Storage限制,可改用
MediaStoreAPI保存文件,避免依赖外部存储权限。 - 注入的JS代码需注意字符转义,避免因特殊字符导致语法错误。
内容的提问来源于stack exchange,提问作者Sanyam Patel
相关产品推荐
相关产品推荐

