Android 10+ 中访问媒体文件需要哪些权限?

解读

国内面试场景下,这道题考察的是“权限模型 + 分区存储(Scoped Storage)”两条主线。
面试官想确认两点:

  1. 你是否把“普通读取”和“全盘扫描”区分清楚;
  2. 你是否知道 Android 10、11、13 三次政策收紧的差异化表现,以及国内无 GMS 环境下厂商兼容层的坑。
    答得太笼统(只说 READ/WRITE)会被追问“为什么 10 上还能用 legacy?”;答得太细却漏掉“权限拒绝后跳转到系统文件 picker”的补救方案,会被认为业务经验不足。

知识点

  1. 分区存储(Scoped Storage) timeline

    • Android 10:默认开启,但 requestLegacyExternalStorage=true 可回退。
    • Android 11:强制开启,legacy flag 失效;引入 MANAGE_EXTERNAL_STORAGE(俗称“所有文件访问”)。
    • Android 13:细化媒体权限,READ_MEDIA_IMAGES/VIDEO/AUDIO 取代旧的 READ_EXTERNAL_STORAGE。
  2. 权限粒度

    • 读取图片/视频/音频:READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO(API 33+)。
    • 写入媒体:无需 WRITE_EXTERNAL_STORAGE,只要文件落入公共目录且 MIME 类型匹配,MediaStore 自动授权。
    • 访问非媒体文件(PDF、DOC、APK):必须使用 Storage Access Framework(SAF),Intent.ACTION_OPEN_DOCUMENT;无法通过路径直接访问。
    • 访问任意路径 /sdcard/Android/data、/sdcard/obb:既无权限也跳不过 Scoped Storage,除非用户手动授权“所有文件访问”(MANAGE_EXTERNAL_STORAGE),而国内上架应用市场几乎不可能通过审核。
  3. 国内厂商兼容层

    • 小米、OPPO 在 Android 11 上仍提供“文件管理器授权”快捷入口,但系统返回的 URI 可能缺少 FLAG_GRANT_PERSISTABLE_URI_PERMISSION,需在 onActivityResult 里 takePersistableUriPermission,否则重启后权限丢失。
    • 华为 HMS 环境没有 Google 的 MediaStore 云端备份字段,但权限模型一致,可直接复用。
  4. 安全审查红线

    • 工信部 164 号文:若 targetSdk≥30,申请 MANAGE_EXTERNAL_STORAGE 必须提交“核心场景”说明,否则直接下架。
    • 主流厂商安全扫描器会静态检测 File(path) 硬编码,发现直接访问 /sdcard/ 路径即视为违规。

答案

“在 Android 10+ 访问媒体文件,首先必须区分‘读取已有媒体’与‘写入新文件’两种场景。

  1. 仅读取图片、视频、音频:
    • 若 targetSdk≤32,申请 READ_EXTERNAL_STORAGE 即可一次性覆盖三种类型;
    • 若 targetSdk≥33,需要分别申请 READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO 三个权限,系统弹窗一次合并提示。
  2. 写入新拍摄/下载的媒体:无需 WRITE_EXTERNAL_STORAGE,直接通过 MediaStore.insert() 返回的 URI 写入即可,系统默认授予目录写权限。
  3. 访问非媒体文件或任意目录:无法通过路径访问,必须退回到 Storage Access Framework,拉起系统文件选择器,由用户手动选择文件;若业务强依赖批量扫描,只能引导用户授予‘所有文件访问’权限(MANAGE_EXTERNAL_STORAGE),但国内上架审核基本会被驳回,因此线上方案应放弃该权限,改用 SAF + MediaStore 组合。”

拓展思考

  1. 如果产品需要“微信式”全量扫描本地相册并做地图时光轴,如何在不申请 MANAGE_EXTERNAL_STORAGE 的前提下实现秒级出图?
    思路:首次启动利用 MediaStore.query() 一次性扫描数据库,把 _ID、DATE_TAKEN、LATITUDE、LONGITUDE 四字段缓存到本地 Room;后续通过 ContentObserver 监听 URI 变更,增量更新,既合规又保证性能。

  2. 当用户拒绝“所有文件访问”后,如何优雅降级?
    可在设置页提供“手动添加目录”按钮,跳转到 SAF 的 Intent.ACTION_OPEN_DOCUMENT_TREE,拿到 URI 后存进 SharedPreferences,并调用 takePersistableUriPermission(),重启后仍可用;同时用 DocumentsContract 遍历子文件,模拟“批量扫描”体验。

  3. Android 14 预计引入 READ_MEDIA_VISUAL_USER_SELECTED 权限,允许用户仅暴露“选中照片”而非整个图库,作为开发者应提前把文件选择逻辑解耦,确保未来只需替换权限常量即可无缝适配。