面向SDK 30(Android 11)如何打开文件管理器选中的外部文件
问题原因
Android 11(API 30)引入了分区存储强制执行机制,同时收紧了URI的访问权限管控,原调用方式抛出安全异常通常是两类原因:
- 仅拿到URI的瞬时访问权限,应用退出/重启后再次访问同一URI就会触发权限校验失败
- 没有正确配置清单文件权限,或存储相关权限申请逻辑不符合分区存储要求
可行解决方案
1. 优先通过系统文件选择器获取永久URI访问权限
不要自行猜测文件路径,统一使用Intent.ACTION_OPEN_DOCUMENT唤起系统文件选择器选文件,选中后主动申请持久化权限,后续就可以长期通过URI访问对应文件:
// 唤起文件选择器选音频的示例代码 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("audio/*"); startActivityForResult(intent, REQUEST_CODE_AUDIO);
在onActivityResult拿到选中的URI后,立即申请持久化权限:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_AUDIO && resultCode == RESULT_OK && data != null) { Uri audioUri = data.getData(); // 申请持久化访问权限 final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); getContentResolver().takePersistableUriPermission(audioUri, takeFlags); // 此时再打开输入流就不会抛安全异常 InputStream inputStream = getContentResolver().openInputStream(audioUri); } }
2. 清单文件权限配置
确保你的AndroidManifest.xml里配置了正确的权限:
<!-- 读取公共媒体文件权限,如果你只需要访问自己应用创建的文件不需要加 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13及以上如果需要访问其他应用创建的音频文件加这个权限 --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- 不要申请MANAGE_EXTERNAL_STORAGE权限,除非你的应用是文件管理器这类需要全局访问文件的工具,否则大概率无法过应用商店审核 -->
3. 临时文件中转方案(适合只需要单次处理音频的场景)
如果你不需要长期访问该文件,拿到URI后可以直接把内容拷贝到你应用的私有目录(context.getFilesDir() 或 context.getCacheDir()),后续直接访问私有目录的文件即可,不需要申请额外权限:
// URI转私有文件示例 public static File uriToFile(Context context, Uri uri, String fileName) throws IOException { File targetFile = new File(context.getCacheDir(), fileName); try (InputStream is = context.getContentResolver().openInputStream(uri); OutputStream os = new FileOutputStream(targetFile)) { byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } } return targetFile; }
内容的提问来源于stack exchange,提问作者user1026605
相关产品推荐
相关产品推荐

