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自动处理文件写入逻辑。
关键说明
- 通过
fetchAPI获取blob的实际内容,再用FileReader转换为base64格式传递,绕开系统无法识别blob:URI的问题。 - 从
contentDisposition头信息解析文件名,保证下载文件的名称与原文件一致。 - 普通下载请求仍使用系统下载管理器,维持原有兼容性。
内容的提问来源于stack exchange,提问作者Aswin MM
相关产品推荐
相关产品推荐

