Android 13及以上设备FileNotFoundException权限问题求助
Android 13+ 任意文件访问权限问题解决方案
问题复盘
在Android 13及以上设备中,写入/storage/emulated/0/Download/MyTest.apk时触发EACCES (Permission denied)异常,即使文件已存在;现有权限仅能获取音频、视频、照片的访问权限,而相同功能在Android 11可正常运行。
先纠正权限声明中的错误
你添加的权限列表存在多处无效写法:
ACTION_OPEN_DOCUMENT_TREE、ACTION_OPEN_DOCUMENT、ACTION_CREATE_DOCUMENT是Intent动作,并非权限,不能放在<uses-permission>标签内READ_MEDIA_*、WRITE_MEDIA_*这类通配符写法无效,Android 13的媒体权限为具体的READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO,且不存在WRITE_MEDIA_*系列权限READ_MEDIA_FILES*多了多余星号,正确写法为READ_MEDIA_FILES(Android 14新增的媒体文件权限)
方案1:使用MANAGE_EXTERNAL_STORAGE权限(直接访问所有文件)
这是唯一能通过文件路径直接访问任意文件的方式,但Google对该权限的应用审核极为严格,仅文件管理器、备份工具等特定类型应用可通过审核。
- 清单中正确声明权限:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" /> - 需跳转至系统设置页让用户手动开启权限(无法通过普通权限申请流程获取):
if (!Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); } - 通过
Environment.isExternalStorageManager()检查权限是否授权成功
方案2:使用Storage Access Framework(SAF,推荐,符合Google政策)
若你的应用不属于文件管理器类,推荐使用SAF——通过用户手动选择文件/目录的方式操作,无需特殊权限审核。
写入Download目录APK文件示例:
- 发起创建/选择文件的Intent:
private static final int REQUEST_CODE_CREATE_FILE = 1001; // 触发文件选择/创建流程 public void createApkFile() { Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("application/vnd.android.package-archive"); // APK对应的MIME类型 intent.putExtra(Intent.EXTRA_TITLE, "MyTest.apk"); startActivityForResult(intent, REQUEST_CODE_CREATE_FILE); } - 在回调中获取文件Uri并写入数据:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_CREATE_FILE && resultCode == RESULT_OK) { Uri fileUri = data.getData(); // 通过ContentResolver写入数据 try (OutputStream outputStream = getContentResolver().openOutputStream(fileUri)) { // 在这里写入你的文件内容到outputStream中 } catch (IOException e) { e.printStackTrace(); } } } - 若需操作整个目录,可使用
ACTION_OPEN_DOCUMENT_TREE让用户选择目标目录,之后即可访问该目录下的所有文件。
权限变化原因
Android 11引入分区存储机制,当targetSdkVersion<30时,WRITE_EXTERNAL_STORAGE仍可部分生效;但Android 13彻底收紧权限:仅媒体文件可通过媒体权限访问,APK等非媒体文件必须通过SAF或MANAGE_EXTERNAL_STORAGE权限操作。
内容的提问来源于stack exchange,提问作者Chamin Thilakarathne
相关产品推荐
相关产品推荐

