Scoped Storage:分区存储与媒体权限
2026/8/9大约 3 分钟存储与多媒体Android 14Scoped StorageMediaStore权限
Scoped Storage:分区存储与媒体权限
上一章建立了存储全景。这一章回答:Scoped Storage 是什么,媒体文件怎么访问, READ_MEDIA 权限与 MANAGE_EXTERNAL_STORAGE 的区别是什么?
Scoped Storage 改变访问模型
| 常见误解 | 正确理解 |
|---|---|
| Scoped Storage 只是“新权限” | 它是外部存储的访问模型变化,不只是权限 |
| 拿到存储权限就能读所有文件 | 权限只覆盖媒体类别;其他文件走 SAF 或受限 |
| MANAGE_EXTERNAL_STORAGE 是常规选择 | 它是特殊权限(All files access),需要说明用途 |
核心结论
- 应用可自由访问自身目录与自建媒体文件。
- 访问共享媒体通过 MediaStore + READ_MEDIA_* 权限。
- 非媒体共享文件通过 SAF(系统文件选择器)获取。
- MANAGE_EXTERNAL_STORAGE 是特殊权限,仅特定场景使用。
- Android 13+ 媒体权限细化为图片/视频/音频三类。
访问模型主链
逐步解释:
- 自身目录:无需权限。
- 自建媒体:通过 MediaStore 写入并归自己。
- 共享媒体:媒体权限 + 查询。
- 其他文件:SAF 选择器。
- 特殊场景:All files access。
媒体权限速查
| 权限 | 覆盖 |
|---|---|
| READ_MEDIA_IMAGES | 图片 |
| READ_MEDIA_VIDEO | 视频 |
| READ_MEDIA_AUDIO | 音频 |
| MANAGE_EXTERNAL_STORAGE | 全部文件(特殊) |
按需申请最小权限,避免使用 MANAGE_EXTERNAL_STORAGE。
源码证据
阅读目标:确认 MediaStore 与权限入口。
正文指针:MediaStore.java 的 URI 与查询;Manifest.java 的媒体权限声明。
// MediaStore.java(伪代码,行号以 r75 为准)
public static final String AUTHORITY = "media";
// content://media/external/images/media 等 URI这段代码证明: 共享媒体统一走 MediaStore URI;权限控制查询范围,SAF 兜底 非媒体文件。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell content query --uri content://media/external/images/media --projection _id:_display_name
adb shell dumpsys package <包名> | grep -E "READ_MEDIA|MANAGE_EXTERNAL"
adb shell pm grant <包名> android.permission.READ_MEDIA_IMAGES先确认应用请求的权限类别,再查 MediaStore 查询结果。媒体读不到先分清:权限没授、 查询范围不对,还是文件不在索引里。
常见误区
- “Scoped Storage 就是新权限”:是访问模型变化。
- “有存储权限就能读一切”:媒体权限分三类。
- “MANAGE_EXTERNAL_STORAGE 是首选”:特殊权限,谨慎。
- “直接拼路径读共享文件”:共享媒体要走 MediaStore。
延伸问题
- Android 13 媒体权限与旧权限的兼容逻辑是什么?
- MediaStore 写入后如何保证自己可访问?
- SAF 返回的 URI 权限如何持久化?
- 大文件(如视频)在 MediaStore 下如何高效访问?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
MediaStore.java | URI 定义 | 媒体索引 |
Manifest.java | 媒体权限 | 授权声明 |
| SAF | 文件选择 | 非媒体访问 |
MediaProvider | 索引服务 | 数据来源 |
公共路径:frameworks/base/media/java/android/provider/ 与 frameworks/base/core/java/android/。行号以 r75 检索为准。
媒体文件如何进入查询数据库,见 MediaProvider。