API 31下@ionic-native/zip报错EACCES权限拒绝问题求助
解决Ionic-Cordova升级Android API31后cordova-plugin-zip权限拒绝问题
问题分析
升级到Android API31后,即便配置了android:requestLegacyExternalStorage="true",且通过权限插件确认READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE已授权,直接访问公共存储(如/storage/emulated/0/Download/)内的文件仍会触发EACCES (Permission denied)错误。核心原因是Android 11+的分区存储机制对公共目录的直接路径访问做了严格限制,requestLegacyExternalStorage在API31+上的兼容效果有限,而cordova-plugin-zip底层仍依赖传统文件IO读取路径,导致权限校验失败。
解决方案
1. 升级cordova-plugin-zip至最新版本
优先确认插件是否已适配API31+,执行命令升级:
cordova plugin remove cordova-plugin-zip cordova plugin add cordova-plugin-zip@latest
2. 规避公共存储绝对路径,改用兼容方式访问文件
- 应用私有目录存储:将待解压文件下载到应用私有目录(如
cordova.file.dataDirectory),此目录下的文件访问无需额外权限,cordova-plugin-zip可直接处理。 - 通过cordova-plugin-file获取合法文件句柄:针对公共Download目录的文件,先通过
resolveLocalFileSystemURL获取FileEntry,再转换为插件可识别的路径:
window.resolveLocalFileSystemURL('file:///storage/emulated/0/Download/some-file.KMZ', function(fileEntry) { fileEntry.file(function(file) { Zip.unzip(file.localURL, cordova.file.dataDirectory + 'unzip/', () => console.log('解压成功'), (err) => console.error('解压失败', err) ); }); }, (err) => console.error('获取文件失败', err));
3. 修改cordova-plugin-zip源码适配Content URI
若必须访问公共目录文件,可修改插件Zip.java中的unzipSync方法,替换直接路径读取逻辑为Content URI兼容处理:
// 替换原InputStream获取逻辑 Uri uri = Uri.parse(sourceUri); InputStream in; if ("content".equals(uri.getScheme())) { in = cordova.getActivity().getContentResolver().openInputStream(uri); } else { in = cordova.getResourceApi().openForRead(sourceUri); }
修改后重新编译插件即可生效。
4. 通过存储访问框架(SAF)获取文件URI
引导用户通过系统文件选择器选择文件,获取Content URI后传入解压方法:
document.addEventListener('deviceready', function() { window.plugins.intentShim.getUri(function(uri) { Zip.unzip(uri, cordova.file.dataDirectory + 'unzip/', () => console.log('解压成功'), (err) => console.error('解压失败', err) ); }, (err) => console.error('获取URI失败', err)); });
关键提示
- Android 12+已不再完全支持
requestLegacyExternalStorage,必须适配分区存储机制。 - 公共存储文件访问优先使用Content URI而非绝对路径,从根源避免权限问题。
内容的提问来源于stack exchange,提问作者David Lopes
相关产品推荐
相关产品推荐

