Android 10设备WebView下载PDF变为.bin文件问题求助
解决Android 10 WebView下载文件变为.bin的问题
我来帮你搞定这个困扰你的问题:在Android 10设备的WebView里下载文件会变成.bin格式,但低版本系统正常,结合你给出的代码,主要是Android 10的存储适配和文件名解析逻辑导致的,下面是具体的解决步骤:
一、问题根源分析
- Scoped Storage 影响:Android 10引入了分区存储(Scoped Storage),
DownloadManager的setDestinationInExternalPublicDir方法在这个版本下的行为发生了细微变化,可能导致文件名解析异常。 - 文件名解析失效:
URLUtil.guessFileName在某些场景下(比如服务器返回的contentDisposition格式不标准,或者MIME类型缺失)无法正确提取文件名和扩展名,最终默认生成.bin后缀的文件。
二、具体解决方案
1. 手动解析Content-Disposition获取正确文件名
URLUtil.guessFileName依赖的参数可能在Android 10下没有被正确传递,我们可以手动从contentDisposition头里提取文件名,这是最可靠的方式:
先添加一个解析文件名的工具方法:
private String extractFileNameFromContentDisposition(String contentDisposition) { if (contentDisposition == null || contentDisposition.isEmpty()) { return null; } // 匹配Content-Disposition中的filename字段 Pattern fileNamePattern = Pattern.compile("filename=\"?([^\"]+)\"?", Pattern.CASE_INSENSITIVE); Matcher matcher = fileNamePattern.matcher(contentDisposition); if (matcher.find()) { return matcher.group(1); } return null; }
然后修改你的onDownloadRequested方法,优先用这个工具方法提取文件名,再兜底用URLUtil.guessFileName:
@Override public void onDownloadRequested(String url, String suggestedFilename, String mimeType, long contentLength, String contentDisposition, String userAgent) { DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setMimeType(mimeType); // 获取Cookie并添加请求头 String cookies = CookieManager.getInstance().getCookie(url); request.addRequestHeader("cookie", cookies); request.addRequestHeader("User-Agent", userAgent); request.setDescription("Downloading file..."); // 优先从Content-Disposition提取文件名,避免解析失败 String fileName = extractFileNameFromContentDisposition(contentDisposition); if (fileName == null || fileName.isEmpty()) { // 如果提取失败,再用URLUtil的方法兜底 fileName = URLUtil.guessFileName(url, contentDisposition, mimeType); } // 额外补全扩展名(如果文件名没有后缀) if (fileName != null && !fileName.contains(".")) { String extension = MimeTypeMap.getFileExtensionFromUrl(url); if (extension != null && !extension.isEmpty()) { fileName += "." + extension; } } request.setTitle(fileName); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // 适配Android 10+的存储路径 request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); dm.enqueue(request); Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show(); Log.d("dsfgh", "onDownloadRequested: "+url); }
2. 添加Legacy存储兼容(临时方案)
如果上述修改后还有问题,可以在AndroidManifest.xml的<application>标签里添加以下属性,让应用在Android 10下使用旧的存储模型:
<application ... android:requestLegacyExternalStorage="true"> ... </application>
这个属性会让应用绕过Scoped Storage的限制,暂时恢复到Android 9及以下的存储行为,适合快速解决兼容问题。
三、额外检查点
- 确认服务器返回的
contentDisposition头是否包含正确的filename字段,比如:Content-Disposition: attachment; filename="example.pdf" - 检查MIME类型是否正确,比如PDF文件应该返回
application/pdf,如果MIME类型错误,也会导致扩展名解析失败。
内容的提问来源于stack exchange,提问作者Rishikesh Rahi
相关产品推荐
相关产品推荐

