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

Android WebView下载PDF时触发“仅支持HTTP/HTTPS URI”异常的问题排查求助

Android WebView下载PDF时触发“仅支持HTTP/HTTPS URI”异常的问题排查求助

我来帮你分析下这个问题~核心原因其实很明确:Android WebView的默认下载处理器只认HTTP/HTTPS开头的URI,而你JS里用URL.createObjectURL(blob)生成的是blob://协议的链接,这就触发了那个IllegalArgumentException。浏览器(比如Chrome)本身支持处理Blob链接的下载,但WebView的安全限制更严格,默认不允许这种本地协议的下载请求。

下面给你几个可行的解决方案,你可以根据自己的需求选择:

方案一:自定义WebView下载监听,适配Blob下载(推荐)

这个方案需要Android原生代码和JS配合,让Native来处理Blob数据的保存:

  1. Android端修改WebView配置:
    给WebView设置自定义的DownloadListener,识别Blob协议并通过JS交互获取数据:

    webView.setDownloadListener(new DownloadListener() {
        @Override
        public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
            if (url.startsWith("blob:")) {
                // 调用JS方法获取Blob的Base64数据
                webView.evaluateJavascript("getBlobData('" + url + "')", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String base64Data) {
                        if (base64Data == null || base64Data.isEmpty()) {
                            Toast.makeText(getApplicationContext(), "获取下载数据失败", Toast.LENGTH_SHORT).show();
                            return;
                        }
                        // 解码Base64并保存为文件
                        try {
                            // 去掉JS传递过来的引号(evaluateJavascript会自动加引号)
                            String cleanData = base64Data.replace("\"", "");
                            byte[] blobBytes = Base64.decode(cleanData, Base64.DEFAULT);
                            // 保存到应用下载目录
                            File downloadDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
                            File pdfFile = new File(downloadDir, "Report Sheet.pdf");
                            FileOutputStream fos = new FileOutputStream(pdfFile);
                            fos.write(blobBytes);
                            fos.close();
                            // 提示用户下载完成
                            Toast.makeText(getApplicationContext(), "PDF已下载到" + pdfFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
                        } catch (Exception e) {
                            e.printStackTrace();
                            Toast.makeText(getApplicationContext(), "下载失败", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            } else {
                // 正常HTTP/HTTPS链接,用系统下载管理器处理
                Intent downloadIntent = new Intent(Intent.ACTION_VIEW);
                downloadIntent.setData(Uri.parse(url));
                startActivity(downloadIntent);
            }
        }
    });
    
  2. JS端添加辅助方法:
    新增一个getBlobData方法,把Blob转成Base64格式传递给Native:

    function getBlobData(blobUrl) {
        return new Promise((resolve) => {
            fetch(blobUrl)
                .then(response => response.blob())
                .then(blob => {
                    const reader = new FileReader();
                    reader.onloadend = () => {
                        // 去掉Base64前缀,只传递纯数据部分
                        const base64Str = reader.result.split(',')[1];
                        resolve(base64Str);
                    };
                    reader.readAsDataURL(blob);
                })
                .catch(err => {
                    console.error("获取Blob数据失败:", err);
                    resolve(null);
                });
        });
    }
    

方案二:直接让WebView处理原始HTTP下载

如果你不需要在JS里精细控制下载进度,可以修改JS逻辑,直接触发原始的HTTP下载请求,跳过Blob转换步骤:

function utils_teacher_progressDownload_get(url, apptype, modal, defaultfilename) {
    if (modal) {
        $('#' + modal).modal({backdrop: 'static', keyboard: false},'show');
    }
    // 直接创建a标签指向原始URL,让WebView触发下载请求
    const a = document.createElement("a");
    a.href = url;
    a.download = defaultfilename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);

    // 这里需要Native配合,在下载完成/失败时通知JS关闭模态框
    // 比如通过WebView的JavascriptInterface发送回调
}

这种方式的缺点是JS无法直接获取下载进度,需要Native在下载开始、完成、失败时通过JavascriptInterface通知JS更新模态框状态。

方案三:尝试开启WebView的Blob访问权限(兼容性有限)

你可以给WebView设置以下参数,尝试让它支持Blob协议的下载,但注意这个方案在Android 11及以上版本可能因为安全限制失效:

WebSettings webSettings = webView.getSettings();
webSettings.setAllowFileAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);

最后给你两个调试小技巧:

  • 在JS里console.log(url),确认生成的链接确实是blob:开头的;
  • 在Android的DownloadListener里打印url,验证触发异常的请求来源。

备注:内容来源于stack exchange,提问作者Kira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 08:39:52