Android已申请存储权限读取外部Excel仍报EACCES权限拒绝问题
问题原因
- 核心时序错误:
ActivityCompat.requestPermissions是异步方法,调用后不会阻塞等待用户操作,会直接执行后续代码。你在发起权限申请后立刻执行了文件读取逻辑,此时权限弹窗尚未得到用户响应,应用还未拿到读取权限,自然抛出EACCES错误,等用户完成授权操作后权限回调才会触发,所以错误日志的输出时间早于你在回调里写的成功日志。 - 高版本系统权限适配缺失:你声明的
READ_EXTERNAL_STORAGE权限存在版本兼容问题:- 项目
targetSdkVersion >= 33(Android 13)时,该权限已被拆分废弃,无法用于访问公共存储文件 - 项目
targetSdkVersion >= 30(Android 11)时,分区存储强制生效,仅持有READ_EXTERNAL_STORAGE无权直接通过文件路径访问公共Documents目录内容
- 项目
修复步骤
- 调整代码执行顺序
把Excel读取逻辑从权限申请代码的后方,移动到权限回调的授权成功分支中,参考实现:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1001) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 确认授权成功后再执行文件读取 loadTodoFile(); } else { // 处理授权拒绝逻辑,比如弹窗提示权限必要性 } } } private void loadTodoFile() { try { File docDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS); File targetFile = new File(docDir, "todo.xlsx"); InputStream inp = new FileInputStream(targetFile); // 执行后续POI解析逻辑 } catch (Exception e) { e.printStackTrace(); } }
- 适配高版本Android存储规则
根据你的应用场景二选一即可:
- 场景A:应用本身是文件管理、文档处理类工具,必须直接通过路径访问公共存储文件
在AndroidManifest.xml补充权限声明:
针对Android 11及以上系统,引导用户跳转系统设置页开启「所有文件访问权限」,注意该权限有严格的上架审核要求,非必要场景不要使用。<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> - 场景B:仅需要读取指定的Excel文件,不需要全量存储访问权限
不需要申请任何存储权限,直接使用系统存储访问框架(SAF)拉起系统文件选择器,让用户手动选中目标todo.xlsx,拿到系统返回的文件Uri后即可直接获取输入流进行POI解析,该方案兼容所有Android版本,无上架审核风险。
补充说明:Android 10及以下版本设备,只要调整完代码时序,原有
READ_EXTERNAL_STORAGE权限即可正常工作,不需要额外适配。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

