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

Android WebView中Internxt文件下载崩溃问题求助

解决Android WebView无法下载Internxt blob URI文件的问题

问题根源

崩溃的核心原因是Android系统默认下载处理器无法识别blob:开头的URI——这类URI是浏览器内部生成的临时对象,并非直接的远程文件地址,直接传递给系统下载器会触发IllegalArgumentException。

解决方案

需要自定义WebView的下载监听,拦截blob类型的下载请求,通过JavaScript获取blob的实际文件数据,再由Android端完成文件写入。以下是针对HomeFragment的具体修改步骤:

1. 配置WebView基础交互能力

确保WebView启用JavaScript,并允许与Android端交互:

// 在HomeFragment的WebView初始化代码中添加
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(WebAppInterface(requireContext()), "AndroidDownloader")

2. 实现JS交互接口(接收文件数据)

创建内部类,用于接收JavaScript传递的文件base64数据并写入本地:

class WebAppInterface(private val context: Context) {
    @JavascriptInterface
    fun downloadFile(base64Data: String, fileName: String) {
        // 将base64数据转换为字节数组
        val bytes = Base64.decode(base64Data, Base64.DEFAULT)
        // 适配Android 10+的Scoped Storage写入文件
        val outputUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI.buildUpon()
            .appendQueryParameter(MediaStore.QUERY_PARAMETER_DISPLAY_NAME, fileName)
            .appendQueryParameter(MediaStore.QUERY_PARAMETER_MIME_TYPE, "application/octet-stream")
            .build()
        
        context.contentResolver.openOutputStream(outputUri)?.use { it.write(bytes) }
        Toast.makeText(context, "文件已下载", Toast.LENGTH_SHORT).show()
    }
}

3. 设置自定义DownloadListener拦截下载请求

给WebView设置下载监听,区分blob URI和普通URI分别处理:

webView.setDownloadListener { url, userAgent, contentDisposition, mimeType, contentLength ->
    if (url.startsWith("blob:")) {
        // 注入JS代码,将blob转换为base64并传递给Android端
        val fileName = contentDisposition.split("filename=")[1].replace(/["']/g, "")
        val jsCode = """
            (function() {
                fetch('$url')
                    .then(response => response.blob())
                    .then(blob => {
                        const reader = new FileReader();
                        reader.onloadend = function() {
                            const base64Data = reader.result.split(',')[1];
                            AndroidDownloader.downloadFile(base64Data, '$fileName');
                        };
                        reader.readAsDataURL(blob);
                    });
            })();
        """.trimIndent()
        webView.post { webView.evaluateJavascript(jsCode, null) }
    } else {
        // 处理普通HTTP/HTTPS下载请求,使用系统下载管理器
        val fileName = contentDisposition.split("filename=")[1].replace(/["']/g, "")
        val request = DownloadManager.Request(Uri.parse(url))
            .setMimeType(mimeType)
            .setTitle(fileName)
            .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
            .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
        
        val downloadManager = requireContext().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        downloadManager.enqueue(request)
    }
}

4. 权限配置

  • Android 10及以下:在AndroidManifest.xml中添加存储权限
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Android 11+:无需额外权限,Scoped Storage自动处理文件写入逻辑。

关键说明

  • 通过fetch API获取blob的实际内容,再用FileReader转换为base64格式传递,绕开系统无法识别blob: URI的问题。
  • 从contentDisposition头信息解析文件名,保证下载文件的名称与原文件一致。
  • 普通下载请求仍使用系统下载管理器,维持原有兼容性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 11:15:36