Android 存储权限与文件系统演进全解析(Android 10 → 16)

随着 Android 系统持续演进(最新已到 Android 16),存储体系已经从传统"文件路径访问模型"彻底转向"系统托管数据访问模型"。

本文从工程视角系统梳理:

  • 存储权限变化
  • File API 的真实边界
  • MediaStore 标准用法
  • SAF 文件访问机制
  • targetSdkVersion=30 的现实行为
  • Android 13~16 的趋势变化

一、核心变化:Scoped Storage(分区存储)

从 Android 10 开始引入,并在 Android 11 强制执行:

👉 Android 11

核心目标:

❗限制 App 对"整个文件系统"的自由访问能力


📦 三层存储模型(现代 Android)

1️⃣ App 私有存储(File 完全可用)

  • /data/data/包名/
  • /Android/data/包名/

特点:

  • 不需要权限
  • File API 完全可用
  • 永久稳定

2️⃣ 媒体存储(MediaStore 管理)

  • DCIM
  • Pictures
  • Movies
  • Music

特点:

  • 必须通过 MediaStore
  • 由系统统一管理
  • 可被相册识别

3️⃣ 任意文件(SAF 管理)

  • Download
  • Documents
  • 用户自选文件

特点:

  • 用户授权访问
  • 无路径直接访问能力
  • 用 Uri 操作

二、targetSdkVersion = 30 的真实情况

在 Android 11 环境(targetSdk=30):

✔️ 仍然存在:

xml 复制代码
READ_EXTERNAL_STORAGE

但:

  • 不再是"全盘访问权限"
  • 仅控制媒体读取范围

❌ 已废弃:

  • WRITE_EXTERNAL_STORAGE(无实际控制能力)
  • legacy storage(requestLegacyExternalStorage)

三、File API 可用边界(非常关键)

✔️ 1. App 私有目录(完全安全)

java 复制代码
context.getFilesDir()
context.getExternalFilesDir()

特点:

  • 永远可用
  • 不依赖权限
  • Android 10~16 稳定

⚠️ 2. 公共存储(DCIM / Download)

java 复制代码
new File("/sdcard/DCIM/xxx.jpg")

现状:

Android版本 行为
Android 10 ⚠️ 可能可用
Android 11 ⚠️ 不保证
Android 13+ ❌ 严格限制
Android 16 ❌ 不可靠行为

👉 本质:非规范访问方式


四、DCIM 写入的标准方式(MediaStore)

✔️ 正确方式:写入相册

java 复制代码
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "img.jpg");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.RELATIVE_PATH, "DCIM/MyApp");
values.put(MediaStore.Images.Media.IS_PENDING, 1);

ContentResolver resolver = context.getContentResolver();

Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

if (uri != null) {
    OutputStream os = resolver.openOutputStream(uri);
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
    os.close();

    values.clear();
    values.put(MediaStore.Images.Media.IS_PENDING, 0);
    resolver.update(uri, values, null, null);
}

✔️ 特点:

  • 自动进入相册
  • 不需要存储权限
  • Android 10~16 完全稳定
  • 系统统一索引管理

五、读取文件方式演进

1️⃣ 读取相册(标准)

java 复制代码
Cursor cursor = resolver.query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        null,
        null,
        null,
        MediaStore.Images.Media.DATE_ADDED + " DESC"
);

读取:

java 复制代码
InputStream is = resolver.openInputStream(uri);

2️⃣ 任意文件读取(SAF)

java 复制代码
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("*/*");
startActivityForResult(intent, 100);

3️⃣ File 直接读取公共目录(不推荐)

java 复制代码
new File("/sdcard/Download/a.json")

现状:

  • ⚠️ 部分设备可用
  • ❌ Android 13+ 不可靠
  • ❌ Android 16 不保证行为

六、为什么"File 写 DCIM 仍然能成功"

在现实设备中仍可能看到成功现象:

1️⃣ MediaScanner 兜底机制

系统扫描媒体目录并索引文件


2️⃣ 厂商兼容策略

例如:

  • Xiaomi
  • OPPO
  • Vivo

可能仍保留旧行为兼容


3️⃣ targetSdk=30 的兼容窗口

旧行为尚未完全收紧


👉 关键结论:

❗"能写成功 ≠ 官方支持方案 ≠ 长期可用"


七、Android 13+ 权限模型变化

在 Android 13:

权限拆分为:

text 复制代码
READ_MEDIA_IMAGES
READ_MEDIA_VIDEO
READ_MEDIA_AUDIO

趋势:

  • 减少统一存储权限
  • 增强用户控制
  • 推广 Photo Picker(无权限访问)

八、工程对照表(完整版本)

📊 存储访问全对照表

场景 File API MediaStore SAF 权限 稳定性 Android 16趋势
App内部存储 ✔️ ⭐⭐⭐⭐⭐ 不变
App外部私有 ✔️ ⭐⭐⭐⭐⭐ 不变
写入DCIM ⚠️ ✔️ ⭐⭐⭐ 强制MediaStore
读取DCIM ⚠️ ✔️ READ_MEDIA_* ⭐⭐⭐ MediaStore
写视频 ⚠️ ✔️ ⭐⭐⭐ MediaStore
下载目录写入 ⚠️ ✔️ ✔️ ⭐⭐ SAF优先
下载目录读取 ⚠️ ✔️ SAF ⭐⭐ SAF
任意文件 ✔️ ⭐⭐⭐⭐⭐ SAF唯一

九、工程迁移策略

🟢 可不改

  • App内部 File
  • cache / log / json

🟡 建议改

  • DCIM读取 → MediaStore
  • Download读取 → SAF

🔴 必须改

  • 写入相册
  • 媒体生成
  • 公共文件写入

十、核心总结

Android 存储体系已经形成三大模型:

📦 1. File(仅限私有空间)

  • 永久稳定
  • 不依赖权限

📷 2. MediaStore(媒体系统)

  • 相册 / 视频 / 音频
  • 系统托管

📁 3. SAF(用户文件)

  • 任意文件访问
  • 用户授权控制

十一、最终结论

Android 存储体系已经从"文件路径访问模型"演进为"系统托管数据模型 + 用户授权模型"。File API 仅在 App 私有空间稳定有效,而公共存储在 Android 11 起逐步收紧,在 Android 16 已完全转向 MediaStore 与 SAF 主导的体系。


相关推荐
seabirdssss2 小时前
从 Windows GUI 自动化到 Android 自动化:一套双端巡检脚本的重构过程
android·windows·自动化
winfredzhang2 小时前
Android中安装模拟器失败,清理安装失败的模拟器
android·清理·模拟器
ganshenml2 小时前
Android PopupWindow 在老年模式下定位偏移问题分析与解决(showAtLocation / 字体缩放 / 抖动)
android
summerkissyou19872 小时前
Android-SurfaceView-投屏-例子
android·surfaceview
Kapaseker3 小时前
我再也不用求设计做阴影了 — Compose 阴影
android·kotlin
Digitally3 小时前
6 种简单方法:在 Mac 电脑与安卓手机之间传输文件
android
鹏程十八少3 小时前
3. 2026金三银四 Android 背完这 23 道题,Android 线程面试横着走
android·面试·前端框架
冬奇Lab13 小时前
Android 开发要变天了:Google 专为 Agent 重建工具链,Token 减少 70%、速度提升 3 倍
android·人工智能·ai编程
imuliuliang16 小时前
存储过程(SQL)
android·数据库·sql