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

Android从ASP.NET站点下载文件:DownloadManager功能失效求助

问题排查与解决方案

咱们一步步拆解你遇到的问题,先从最核心的点说起:

1. 核心问题:WebView捕获不到JS触发的下载请求

你的站点下载按钮是通过JavaScript:openAttachment('/doc/28-02-2019.xlsx', 283662);触发的,这种JS调用的下载请求不会触发shouldOverrideUrlLoading方法——这个方法只能拦截直接的URL跳转(比如普通的<a href="真实下载链接">),对JS发起的请求完全无感。

修复方案:用DownloadListener捕获所有下载请求

这是最简单且无需前端配合的方案,WebView自带的setDownloadListener可以捕获任何类型的下载请求,包括JS触发的:

webView.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
        // 1. 构建下载请求
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        request.setMimeType(mimeType);
        
        // 2. 正确解析文件名(替代你原来的错误拼接逻辑)
        String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);
        if (TextUtils.isEmpty(fileName)) {
            // 兜底方案:用时间戳避免重名
            fileName = "Документ_" + System.currentTimeMillis();
        }
        
        // 3. 配置下载参数
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        
        // 4. 适配不同Android版本的存储权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
        } else {
            // Android 6.0+需要动态申请存储权限
            if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        1001);
                return;
            }
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
        }
        
        // 5. 执行下载
        DownloadManager dManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        if (dManager != null) {
            dManager.enqueue(request);
            Toast.makeText(MainActivity.this, "开始下载文件", Toast.LENGTH_SHORT).show();
        }
    }
});

2. 文件名拼接的低级错误

你原来的代码里:

String fileName = "Документ" + url.startsWith(".");

url.startsWith(".")返回的是布尔值(true/false),导致文件名变成Документtrue或者Документfalse,这显然不是你想要的。上面的方案里用URLUtil.guessFileName已经完美解决了这个问题,它会从URL、响应头里自动解析出正确的文件名。

3. 存储权限的适配细节

  • Android 6.0+:必须动态申请WRITE_EXTERNAL_STORAGE权限,否则DownloadManager无法写入外部存储;
  • Android 10+:默认启用Scoped Storage,如果你想继续使用公共下载目录,需要在AndroidManifest.xml的<application>标签里添加:
android:requestLegacyExternalStorage="true"

4. 修正shouldOverrideUrlLoading的返回值

你原来的方法最后返回true,会导致所有非下载链接也被拦截,页面无法正常加载。正确的写法应该是:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    // 仅拦截直接的下载链接(可选,因为主要下载逻辑已经交给DownloadListener)
    if (url.endsWith(".xlsx") || url.endsWith(".xls") || url.endsWith(".pdf") || url.endsWith(".doc")) {
        // 这里可以复用DownloadListener里的下载逻辑
        return true;
    }
    // 非下载链接,让WebView正常加载
    return false;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:56:57