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

Android WebView 如何获取blob链接数据并下载到设备存储

安卓WebView下载Blob格式文件解决方案

问题1:如何从blob: URL获取对应数据

你现有的JavaScriptInterface方案思路是正确的,只需要修正硬编码适配多格式、补全WebView配置即可正常运行,现有代码存在以下可优化点:

  • 硬编码请求头Content-type为image/gif,仅支持GIF格式,无法适配PDF、PNG等其他类型文件
  • 保存文件时仅移除了GIF格式的base64前缀,其他格式的base64数据无法正确解码
  • 缺少WebView触发下载的拦截逻辑,无法主动捕获blob下载请求

完整实现步骤:

  1. 先配置WebView基础参数
// 开启JS支持
webView.getSettings().setJavaScriptEnabled(true);
// 添加JS交互接口
DownloadBlobFileJSInterface jsInterface = new DownloadBlobFileJSInterface(this);
webView.addJavascriptInterface(jsInterface, "Android");
// 拦截下载请求
webView.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> {
    if (url.startsWith("blob:")) {
        // 执行JS代码获取blob的base64数据
        webView.evaluateJavascript(jsInterface.getBase64StringFromBlobUrl(url), null);
    }
});
  1. 优化后的JSInterface代码,支持多格式文件下载
class DownloadBlobFileJSInterface {
    private Context mContext;
    private DownloadSuccessListener mDownloadSuccessListener;

    public DownloadBlobFileJSInterface(Context context) {
        this.mContext = context;
    }

    public String getBase64StringFromBlobUrl(String blobUrl) {
        if (blobUrl.startsWith("blob")) {
            return "javascript: var xhr = new XMLHttpRequest();" +
                    "xhr.open('GET', '" + blobUrl + "', true);" +
                    "xhr.responseType = 'blob';" +
                    "xhr.onload = function(e) {" +
                    "    if (this.status == 200) {" +
                    "        var blobFile = this.response;" +
                    "        var reader = new FileReader();" +
                    "        reader.readAsDataURL(blobFile);" +
                    "        reader.onloadend = function() {" +
                    "            base64data = reader.result;" +
                    "            Android.getBase64FromBlobData(base64data);" +
                    "        }" +
                    "    }" +
                    "};" +
                    "xhr.send();";
        }
        return "javascript: console.log('It is not a Blob URL');";
    }

    public void setDownloadSuccessListener(DownloadSuccessListener listener) {
        mDownloadSuccessListener = listener;
    }

    @JavascriptInterface
    public void getBase64FromBlobData(String base64Data) {
        convertToFileAndProcess(base64Data);
    }

    private void convertToFileAndProcess(String base64) {
        // 解析base64前缀获取文件类型
        String type = base64.substring(base64.indexOf(":") + 1, base64.indexOf(";"));
        String suffix = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
        if (suffix == null) {
            // 未识别到类型默认用bin
            suffix = "bin";
        }
        ContextWrapper wrapper = new ContextWrapper(mContext);
        String fullPath = wrapper.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();
        File targetFile = new File(fullPath + "/File_" + System.currentTimeMillis() + "." + suffix);
        saveFileToPath(base64, targetFile);
        Toast.makeText(mContext, "下载完成,已保存到Download目录", Toast.LENGTH_SHORT).show();
        if (mDownloadSuccessListener != null) {
            mDownloadSuccessListener.downloadSuccess(targetFile.getAbsolutePath());
        }
    }

    private void saveFileToPath(String base64, File filePath) {
        try {
            // 去掉所有格式的base64前缀
            String pureBase64 = base64.substring(base64.indexOf(",") + 1);
            byte[] fileBytes = Base64.decode(pureBase64, 0);
            FileOutputStream os = new FileOutputStream(filePath, false);
            os.write(fileBytes);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(mContext, "下载失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    public interface DownloadSuccessListener {
        void downloadSuccess(String absolutePath);
    }
}

注意事项:

  • Android 9及以上版本如果访问HTTP站点,需要在AndroidManifest.xml的application节点添加android:usesCleartextTraffic="true"
  • 混淆规则需要添加:-keepclassmembers class * { @android.webkit.JavascriptInterface <methods>; }
  • 不需要额外申请存储权限,getExternalFilesDir是应用专属目录,Android 10及以上无需动态申请权限

问题2:是否可以将blob数据传递给Chrome完成下载

不可以。blob URL是和当前WebView的渲染进程上下文绑定的,仅在当前应用的WebView内存中有效,传递给Chrome后,Chrome没有对应内存中的blob数据,无法识别该链接,因此不能通过跳转Chrome的方式完成下载。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 14:54:09