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 主导的体系。


相关推荐
美狐美颜SDK开放平台1 天前
视频美颜SDK如何实现动态贴纸跟随?人脸追踪技术解析
android·人工智能·计算机视觉·音视频·直播美颜sdk
FLJwu1 天前
运动相机图像传感器选型实战|第二篇:参数看着一模一样,为什么骑行录像疯狂果冻、拖影翻车?
android·c语言·开发语言·数码相机·运动相机·oem 量产
DengDongQi1 天前
Compose 单 Activity 架构实现指南
android·架构·composer
FlightYe1 天前
音视频修炼之容器与协议(二):HLS和DASH流媒体
android·linux·ffmpeg·音视频·android runtime·dash
allanGold1 天前
Android Studio 无线调试
android·ide·android studio
Kapaseker1 天前
AI 会干掉 React Native 吗?
android·kotlin
2501_915921431 天前
iOS 实时日志怎么看?KeyMob 的日志过滤、崩溃报告与符号化
android·ios·小程序·https·uni-app·iphone·webview
千里马学框架1 天前
Service服务绑定对进程adj影响及常见绑定错误
android·智能手机·性能优化·程序员·framework·性能·安卓失业
独隅2 天前
Claude API 实战教程:从入门到完整项目
android·java·数据库·claude·claude code
且随疾风前行.2 天前
Paint Cavans高级绘制:[一]Paint画笔高级应用
android·ui