Android WebView应用如何在内部或跳转外部浏览器下载blob链接的PDF文件
问题根因
你当前代码无法下载blob格式URL的核心原因是系统DownloadManager不支持blob协议,blob是WebView当前会话内的临时内存地址,脱离WebView上下文直接请求会失效。
最简解决方案
步骤1:添加Blob下载JS交互接口
在你的MainActivity中添加如下内部类,用于接收WebView传回的文件内容:
public class DownloadBlobInterface { @JavascriptInterface public void downloadBlobFile(String base64Data, String fileName, String mimeType) { // 异步处理文件写入,避免阻塞JS线程 new Thread(() -> { try { // 去除base64前缀 String base64Content = base64Data.split(",")[1]; byte[] fileBytes = android.util.Base64.decode(base64Content, android.util.Base64.DEFAULT); // 保存到公共下载目录 File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File outputFile = new File(downloadDir, fileName); FileOutputStream fos = new FileOutputStream(outputFile); fos.write(fileBytes); fos.flush(); fos.close(); // 通知下载完成(切换到主线程弹吐司) runOnUiThread(() -> Toast.makeText(MainActivity.this, "文件已保存到下载目录", Toast.LENGTH_SHORT).show()); } catch (Exception e) { runOnUiThread(() -> Toast.makeText(MainActivity.this, "下载失败:" + e.getMessage(), Toast.LENGTH_SHORT).show()); } }).start(); } }
步骤2:给WebView注册JS接口
在WebView初始化配置的位置添加一行代码:
// 原有WebView配置代码不变,新增下面这行 webView.addJavascriptInterface(new DownloadBlobInterface(), "AndroidDownloader");
步骤3:修改DownloadListener逻辑
替换你现有的onDownloadStart方法,区分普通URL和blob URL:
@Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { // 判断是否是blob协议的URL if (url.startsWith("blob:")) { String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); // 拼接执行JS代码,把blob转成base64传回原生 String jsCode = "javascript:(function() {" + "var xhr = new XMLHttpRequest();" + "xhr.open('GET', '" + url + "', true);" + "xhr.responseType = 'blob';" + "xhr.onload = function(e) {" + " if (this.status == 200) {" + " var blob = this.response;" + " var reader = new FileReader();" + " reader.readAsDataURL(blob);" + " reader.onloadend = function() {" + " var base64 = reader.result;" + " AndroidDownloader.downloadBlobFile(base64, '" + fileName + "', '" + mimetype + "');" + " }" + " }" + "};" + "xhr.send();" + "})()"; webView.loadUrl(jsCode); Toast.makeText(MainActivity.this, "正在下载文件...", Toast.LENGTH_SHORT).show(); } else { // 非blob URL走你原来的DownloadManager逻辑 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); String cookies = CookieManager.getInstance().getCookie(userAgent); request.addRequestHeader("cookie",cookies); request.addRequestHeader("User-Agent",userAgent); request.setDescription("Downloading File...."); request.setTitle(URLUtil.guessFileName(url,contentDisposition,mimetype)); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setDestinationInExternalPublicDir( Environment.DIRECTORY_DOWNLOADS,URLUtil.guessFileName(url,contentDisposition,mimetype)); DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); downloadManager.enqueue(request); Toast.makeText(MainActivity.this, "Downloading File...", Toast.LENGTH_SHORT).show(); } }
补充权限配置
在AndroidManifest.xml中添加必要权限:
<!-- Android 13以下存储权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 12+下载通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.INTERNET" />
Android 6.0~12版本需要动态申请WRITE_EXTERNAL_STORAGE权限后再执行下载操作。
内容的提问来源于stack exchange,提问作者iChitti
相关产品推荐
相关产品推荐

