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

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+需动态申请存储权限,确保写入文件时权限正常。

注意事项

  1. 确保WebView已启用JavaScript,否则无法执行Blob转Base64的逻辑。
  2. 针对Android 11+的Scoped Storage限制,可改用MediaStore API保存文件,避免依赖外部存储权限。
  3. 注入的JS代码需注意字符转义,避免因特殊字符导致语法错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 08:25:30