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

Android WebView使用DownloadListener下载特定站点PDF文件崩溃如何解决?

问题原因

  1. 权限适配不到位:Android 10(API 29)以上废弃了WRITE_EXTERNAL_STORAGE权限,未适配分区存储会导致写入文件失败;Android 13(API 33)以上需要POST_NOTIFICATIONS权限才能让DownloadManager发送下载通知,缺少该权限会直接触发崩溃。
  2. 下载请求类型不支持:该站点的PDF下载是POST表单提交触发的,而系统DownloadManager仅默认支持GET请求,直接使用onDownloadStart返回的URL发起GET请求无法拿到正确的文件流,甚至触发异常。
  3. 参数容错缺失:如果接口返回的mimeType、contentDisposition为空或者包含非法字符,URLUtil.guessFileName可能生成非法文件名,调用setDestinationInExternalPublicDir时会触发崩溃。

修复方案

首先修改AndroidManifest.xml的权限与配置:

<!-- 基础网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Android 6.0-9.0 所需存储权限,更高版本无需声明 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<!-- Android 13+ 所需通知权限,用于展示下载进度通知 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application
    ...
    <!-- Android 10 分区存储兼容配置,可直接写入公共下载目录 -->
    android:requestLegacyExternalStorage="true">
    ...
</application>

然后修改运行时权限申请逻辑,适配不同系统版本:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    ArrayList<String> needRequestPermissions = new ArrayList<>();
    // Android 9及以下才需要申请存储权限
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P 
        && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        needRequestPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    // Android 13及以上需要申请通知权限
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU 
        && checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
        needRequestPermissions.add(Manifest.permission.POST_NOTIFICATIONS);
    }
    if (!needRequestPermissions.isEmpty()) {
        requestPermissions(needRequestPermissions.toArray(new String[0]), 1);
    }
}

最后修改DownloadListener逻辑,增加异常捕获和参数容错:

web_view.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
        try {
            // 修复mimeType为空的问题,缺省值设置为PDF类型
            String finalMimeType = mimeType;
            if (TextUtils.isEmpty(finalMimeType)) {
                finalMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));
                if (TextUtils.isEmpty(finalMimeType)) {
                    finalMimeType = "application/pdf";
                }
            }
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
            request.setMimeType(finalMimeType);
            
            String cookies = CookieManager.getInstance().getCookie(url);
            if (!TextUtils.isEmpty(cookies)) {
                request.addRequestHeader("cookie", cookies);
            }
            request.addRequestHeader("User-Agent", userAgent);
            request.setDescription("正在下载文件...");
            
            // 过滤文件名非法字符,避免创建文件失败
            String fileName = URLUtil.guessFileName(url, contentDisposition, finalMimeType);
            fileName = fileName.replaceAll("[^a-zA-Z0-9\\.\\-_]", "_");
            request.setTitle(fileName);
            
            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
            
            DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            dm.enqueue(request);
            Toast.makeText(getApplicationContext(), "正在下载文件,可从文件管理器的下载目录查看", Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            Log.e("DownloadError", "下载失败: ", e);
            Toast.makeText(getApplicationContext(), "下载失败,请稍后重试", Toast.LENGTH_SHORT).show();
        }
    }
});

注意:如果修改后仍无法下载该站点PDF,说明该下载请求是POST类型,系统DownloadManager本身不支持POST下载,需要自行实现网络请求逻辑,拦截WebView的POST请求拿到请求参数后,手动发起请求写入本地文件即可。


内容的提问来源于stack exchange,提问作者Rafiqul Islam Parvez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:45:03