目录
一、分区存储概念
1.外部存储分类
2.分区存储如何影响文件访问
二、分区适配方案
1. 应用分区存储的文件访问规定
(1).应用专属目录--私有目录
(2).共享目录文件--公有目录
2.MediaStore API介绍
3.Storage Access Framework介绍
三、所有文件访问权限
四、总结
一、分区存储概念
1.外部存储分类
可以分为两大类:私有存储和共享存储。
分类 | 路径 | 特点 |
私有存储(私有目录) | /storage/emulated/0/Android/data/包名 | 1)每个应用在内部存储种都拥有自己的私有目录,其它应用看不到,彼此也无法访问到该目录;2)私有目录存放 app 的私有文件,会随着 App的卸载而删除。 |
共享存储(公有目录) | /storage/emulated/0/Downloads(Pictures)) 等 | 1)除了私有存储以外,其他的一切都被认定是共享存储,比如:Downloads、Documents、Pictures 、DCIM、Movies、Music 等;2)公有目录下的文件不会跟随 APP 卸载而被删除 |
在 Android 10 以前,只要程序获得了 READ_EXTERNAL_STORAGE
权限,就可以随意读取外部的存储公有目录;同时只要程序获得了WRITE_EXTERNAL_STORAGE
权限,就可以随意在写入外部存储的公有目录上新建文件或文件夹。
Android 10 开始引进的 Android 系统存储管理机制-- 分区存储,意在限制APP对外部存储中公有目录的使用;APP可以查看外部存储设备内以下类型的文件,无需请求任何与存储相关的用户权限:
应用外部特定目录中(私有目录)的文件(使用getExternalFilesDir()访问)。
应用自己创建的照片、视频和音频(通过MediaStore访问)。
2.分区存储如何影响文件访问
类型 | 位置 | 访问应用自己生成的文件 | 访问其他应用生成的文件 | 访问方法 | 卸载是否删除文件 |
私有存储 | 应用特定的目录(私有目录) | 无需权限 | 无法直接访问 | getExternalFilesDir()获取到属于应用自己的文件路径 | 是 |
共享存储 | Photo/ Video/Audio/ | 无需权限 | 需要权限 READ EXTERNAL STORAGE | MediaStore Api | 否 |
共享存储 | Downloads | 无需权限 | 无需权限 | 通过存储访问框架SAF,加载系统文件选择器 | 否 |
二、分区适配方案
1. 应用分区存储的文件访问规定
(1).应用专属目录--私有目录
每个应用向自己的私有目录读写文件,不需要读写权限。
应用即使获取了读写权限,也无法访问其他应用的私有目录。
私有文件目录具体路径:storage/emulated/0/android/data/packageName/…
访问方式:
this.getExternalCacheDir() this.getExternalFilesDir(Environment.DOWNLOADS)
(2).共享目录文件--公有目录
共享目录文件需要通过MediaStore API或者Storage Access Framework方式访问
①MediaStore API 在共享目录指定目录下创建文件或者访问应用自己创建文件,不需要申请任何存储权限
②MediaStore API访问其他应用在共享目录创建的媒体文件(图片、音频、视频),
需要申请存储权限,未申请存储权限,通过ContentResolver查询不到文件Uri,即使通过其他方式获取到文件Uri,读取或创建文件会抛出异常;
③MediaStore API不能够访问其他应用创建的非媒体文件(pdf、office、doc、txt等), 只能够通过Storage Access Framework方式访问。
2.MediaStore API介绍
Android 系统会自动扫描外部存储空间,将媒体文件按类型添加到系统预定义的 Images、Videos、Audio files、Downloaded files 集合中。
Android 10 通过 MediaStore.Images、MediaStore.Video、MediaStore.Audio、MediaStore.Downloads 访问相对应共享目录文件资源。
MediaStore API创建文件
Android 10版本 MeidaStore API只允许在共享目录指定目录创建文件, 非指定目录创建文件会抛出IllegalArgumentException, 创建文件目录汇总如下:
媒体类型 | Uri | 默认创建目录 | 允许存储文件 |
lmage | content://media/external/images/media | Pictures | 只能放图片 |
Audio | content://media/external/audio/media | Music | 只能放图片 |
Video | content://media/external/video/media | Movies | 只能放视频 |
Download | content://media/external/downloads | Download | 任意类型 |
MediaStore.Downloads.EXTERNAL_CONTENT_URI是Android10版本新增API,用于创建、访问非媒体文件,需要注意的是:虽然获取了存储权限,但是依然不能够删除和修改其他应用的文件。
MediaStore API 文件访问
3.Storage Access Framework介绍
Android 10 里唯一一种访问其他应用创建的非媒体文件的途径是使用存储访问框架 (Storage Access Framework) 提供的文档选择器。SAF 访问外部存储空间的共享目录的文件不需要申请任何权限,原因很简单,它需要启动系统的文件选择器向用户申请操作指定的文件,有用户交互过程的动作本身就是权限管控了,自然也就可以不用预先申请权限。
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");//设置类型--任意类型
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, READ_REQUEST_CODE);
三、所有文件访问权限
分区存储机制很好地规范了 Android App 的存储行为,让它们读自己该读的,写自己该写的。但是有的应用天生就需要对 SD 卡进行全方位的访问,比如各种文件浏览器、垃圾清理软件等等,
对此,Android 11 引入了一个新的权限:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
同时如果要申请此权限,需要打开设置界面,让用户手动设置:
Intent intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
startActivityForResult(intent, 10010)
这个权限就是用来获取所有文件的管理权限,那么是不是可以直接申请这个权限就可以了呢?是可以的,不过应用市场不让上架…所以大部分 App 是不允许使用这个权限的。
如果是文件管理器、备份及存储类的应用。你需要在 Google Play Developer Console 上填写声明表格说明为什么需要 MANAGE_EXTERNAL_STORAGE 权限,提交之后会被审核是否加入白名单,一旦加入成功以后,您的应用就可以向用户索要权限了,如果用户也同意您应用的访问权限请求,MadiaStore 访问将不再过滤,包括非媒体库文件。但是获得此权限的应用仍然无法访问这些目录在存储卷上显示为 Android/data/ 的子目录,也就是属于其他应用的应用专属目录。
四、总结
Android10分区存储之后:
①特定于应用的目录(私有目录) –> 无需权限 –> 访问方法 getExternalFilesDir () –> 卸载应用时移除文件
②访问其他应用创建的--媒体集合 (照片、视频、音频) –> 需要权限 READ_EXTERNAL_STORAGE –> 访问方法 MediaStore –> 卸载应用时不移除文件
③访问其他应用创建的非media文件--下载内容(文档和电子书籍)–> 无需权限 –> 存储访问框架(加载系统的文件选择器)–> 卸载应用时不移除文件Android11又将READ_EXTERNAL_STORAGE 细化为三个权限
总结下 Android 10 之后分区存储机制带来的数据访问的特点和区分: