Android11文件读写报错open failed: EACCES (Permission denied)问题问询
问题原因
- Android 11(API 级别 30)起强制执行分区存储机制,Android 10上生效的
android:requestLegacyExternalStorage="true"配置在API30+系统中完全失效,普通应用默认无法直接通过绝对路径访问公共目录下的第三方文件 - 你当前读取的
/storage/emulated/0/Documents/下的文件属于公共存储目录,普通应用即使申请了READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE权限,也无法直接通过File API访问其他应用生成的公共目录文件,所以抛出EACCES权限拒绝错误 MANAGE_EXTERNAL_STORAGE权限属于特殊权限,仅文件管理器、备份类等特定用途应用可以通过Google Play审核,普通应用申请确实无法过审
合规适配方案(无需申请特殊权限,可正常过审)
以下方案覆盖三类常见使用场景,你可以根据自己的业务需求选择:
场景1:json文件是应用自身生成的配置文件
如果该文件是你的应用生成的,优先存储到应用私有目录,完全不需要申请存储权限,全版本Android系统都可以正常读写:
- 私有文件目录获取方式:
context.getExternalFilesDir(null),对应路径为/storage/emulated/0/Android/data/[你的应用包名]/files/ - 修改后的读取代码参考:
public static JSONObject loadJSONFromAsset(Context context, String relativePath) { JSONObject json = null; // 从应用私有目录读取,无需权限 File rootDir = context.getExternalFilesDir(null); File file = new File(rootDir, relativePath); try { FileInputStream is = new FileInputStream(file); int size = is.available(); byte[] buffer = new byte[size]; is.read(buffer); is.close(); json = new JSONObject(new String(buffer, "UTF-8")); } catch (IOException | JSONException ex) { ex.printStackTrace(); return null; } return json; }
调用时仅需传入相对路径即可,比如"configs/database.json",不需要传入完整绝对路径。
场景2:json文件是用户从外部导入的
如果需要让用户主动选择设备上的json文件导入,使用系统存储访问框架(SAF),不需要申请任何存储权限:
- 启动系统文件选择器让用户选中目标json文件:
private static final int REQUEST_CODE_PICK_JSON = 1001; // 触发文件选择的逻辑 private void pickJsonFile() { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("application/json"); startActivityForResult(intent, REQUEST_CODE_PICK_JSON); }
- 接收选择结果后读取文件内容:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_PICK_JSON && resultCode == RESULT_OK && data != null) { Uri fileUri = data.getData(); try { InputStream is = getContentResolver().openInputStream(fileUri); // 后续读取逻辑和原有逻辑一致,读取完流转JSONObject即可 } catch (IOException e) { e.printStackTrace(); } } }
场景3:json是应用预内置的资源文件
如果该json是打包在APK的assets目录里的预制配置,直接用AssetManager读取即可,不需要任何权限:
public static JSONObject loadJSONFromAsset(Context context, String assetFileName) { JSONObject json = null; try { InputStream is = context.getAssets().open(assetFileName); int size = is.available(); byte[] buffer = new byte[size]; is.read(buffer); is.close(); json = new JSONObject(new String(buffer, "UTF-8")); } catch (IOException | JSONException ex) { ex.printStackTrace(); return null; } return json; }
内容的提问来源于stack exchange,提问作者Ian Pablo
相关产品推荐
相关产品推荐

