Cordova Android WebView无法下载服务器文件如何解决?
Cordova Android WebView 服务器文件下载实现方案
失效原因排查
你之前的方案无报错但不生效,核心是以下3个常见问题没有处理:
- Android 10及以上版本的分区存储权限适配不到位
- WebView默认未开启下载监听逻辑,不会拦截下载请求
- 插件调用时的文件存储路径配置错误
前置配置要求
- 在
config.xml的Android平台配置块中添加权限和适配项:<!-- 基础存储权限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+ 媒体文件权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" android:minSdkVersion="33" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" android:minSdkVersion="33" /> <!-- 适配Android 10分区存储 --> <application android:requestLegacyExternalStorage="true"> <!-- 开启WebView文件访问权限 --> <preference name="AllowFileAccess" value="true" /> <preference name="AllowUniversalAccessFromFileURLs" value="true" /> - 确保Cordova Android平台版本≥10.1.0,低版本对新存储框架适配存在已知bug。
可行实现方案
方案1:原生WebView下载监听(无需额外下载插件)
直接在Android原生层给WebView添加系统下载管理器的监听,兼容性最好:
- 打开项目原生代码的
MainActivity.java,在onCreate方法的loadUrl逻辑后添加如下代码:webView.setDownloadListener((url, userAgent, contentDisposition, mimeType, contentLength) -> { // 动态申请存储权限后再执行下载 if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1001); return; } DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType); request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); dm.enqueue(request); }); - 权限申请回调中如果用户授权,重新触发下载即可。
方案2:cordova-plugin-file + cordova-plugin-file-transfer 正确调用
该方案适合需要在JS层全控制下载逻辑的场景,正确调用写法如下:
// 需先调用权限插件申请存储权限后再执行 const fileTransfer = new FileTransfer(); const downloadUrl = encodeURI("你的服务器文件完整下载地址"); // 必须用公共下载目录路径,私有目录下载后用户不可见 const savePath = cordova.file.externalRootDirectory + 'Download/' + '自定义文件名.后缀'; fileTransfer.download( downloadUrl, savePath, (entry) => { // 下载成功回调,可自行添加打开文件逻辑 console.log("下载完成:" + entry.toURL()); }, (error) => { console.log("下载失败,错误码:" + error.code); }, false, // 若下载需要鉴权,在此处添加请求头 { headers: { "Authorization": "Bearer 你的鉴权令牌" } } );
避坑提示
- 不要直接使用HTML的
download属性,Cordova Android WebView对跨域资源的download属性支持存在缺陷,基本不会触发下载。 - 服务器返回下载响应时必须正确设置
Content-Type和Content-Disposition响应头,否则文件会被WebView直接解析而不是触发下载。 - 所有下载逻辑必须在用户授予存储权限后执行,不要在应用初始化阶段直接调用。
- 调用
cordova-plugin-file-transfer时必须使用cordova.file.externalRootDirectory等公共目录路径,私有目录路径下载的文件用户在系统文件管理器中无法查看。
内容的提问来源于stack exchange,提问作者Andrei George
相关产品推荐
相关产品推荐

