Android 10分区存储权限变更及适配

一、前言

在Android 10中引入了分区储存功能,在外部存储设备中为每个应用提供了一个“隔离存储沙盒”。其他应用无法直接访问应用的沙盒文件。由于文件是应用的私有文件,不再需要任何权限即可访问和保存自己的文件。此变更并有助于减少应用所需的权限数量,同时保证用户文件的隐私性。

  • 目标版本targetSdkVersion设置为28或更低版本以下时,我们对外部存储空间的读写访问需要READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE权限。
  • 目标版本targetSdkVersion设置为29时,可以在应用的清单文件中将加入 android:requestLegacyExternalStorage="true",暂时停用分区存储。继续按上面的方式读写文件。
  • 目标版本targetSdkVersion设置为30时,即要适配Android 11时,分区存储强制执行。

Android 10仍然使用READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE作为存储相关运行时权限,但现在即使获取了这些权限,访问外部存储也受到了限制,只能访问自身目录下的文件和公共内体文件。

无权限 READ_EXTERNAL
Audio 可读写APP自己创建的文件,但不可直接使用路径访问 可以读其他APP创建的媒体类文件,删改操作需要用户授权
Image 可读写APP自己创建的文件,但不可直接使用路径访问 可以读其他APP创建的媒体类文件,删改操作需要用户授权
File 可读写APP自己创建的文件,但不可直接使用路径访问 不可读写其他APP创建的非媒体类文件
Downloads 可读写APP自己创建的文件,但不可直接使用路径访问 不可读写其他APP创建的非媒体类文件

二、内部存储和外部存储

手机内存又有内部存储和外部存储,在以前手机容量不大时,会有外接SD卡,外接的SD卡就是外部存储。如今大部分手机不支持外接SD卡,手机内部就已经自带了外部存储,但不排除少量特殊机型。所以在使用外部存储前应该检查外部存储是否存在:

    /**
     * 检查外部存储是否可读写
     */
    fun isExternalStorageWritable(): Boolean {
   
        return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
    }
    
     /**
     * 检查外部存储是否至少可读取
     */
    fun isExternalStorageReadable(): Boolean {
   
		return Environment.getExternalStorageState() in
        	setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
    }

三、访问应用专属文件

应用无需请求任何与存储空间相关的权限即可访问应用专属目录。卸载应用后,系统会移除这些目录中存储的文件。而该目录下又会有两个子目录,一个目录专为应用的持久性文件而设计,而另一个目录包含应用的缓存文件。

3.1 持久性文件

一般用来放一些长时间保存的数据。

a.内部存储
通过context.filesDir方法可以获取到 /data/data/【应用包名】/files 文件路径
您可以使用 File API 访问和存储文件:

val file = File(context.filesDir, filename)

//or
val file = context.getDir(dirName, Context.MODE_PRIVATE)

除使用 File API 之外,您还可以调用 openFileOutput() 获取会写入 filesDir 目录中的文件的 FileOutputStream

val filename = "myfile"
val fileContents = "Hello world!"
context.openFileOutput(filename, Context.MODE_PRIVATE).use {
   
        it.write(fileContents.toByteArray())
}

如需以信息流的形式读取文件,请使用 openFileInput()

context.openFileInput(filename).bufferedReader().useLines {
    lines ->
    lines.fold("") {
    some, text ->
        "$some\n$text"
    }
}

b.外部存储
通过context.getExternalFilesDir方法可以获取到 sdcard/Android/data/【应用包名】/files 文件路径

val file = File(context.getExternalFilesDir(), filename)

3.2 缓存文件

暂时存储敏感数据,应使用应用在内部存储空间中的指定缓存目录保存数据。当设备的内部存储空间不足时,Android 可能会删除这些缓存文件以回收空间。

a.内部存储
通过context.cacheDir方法可以获取到 sdcard/Android/data/【应用包名】/cache文件路径

val cacheFile = File(context.cacheDir, filename)

//or
val cacheFile = File.createTempFile(filename, null, context.cacheDir)

b.外部存储
通过context.externalCacheDir方法可以获取到 sdcard/Android/data/【应用包名】/cache 文件路径

val file = File(context.getExternalFilesDir(), filename)

四、访问共享存储空间

如果用户数据可供或应可供其他应用访问,并且即使在用户卸载应用后也可对其进行保存,请使用共享存储空间。Android 10更改了应用对设备外部存储设备中的文件(如:/sdcard )的访问方式。继续使用 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 权限,只不过当拥有这些权限的时候,你只能访问媒体文件,无法访问其他文件。

Android 提供用于存储和访问以下类型的可共享数据的 API:

  • 媒体内容: 系统提供标准的公共目录来存储这些类型的文件,这样用户就可以将所有照片保存在一个公共位置,将所有音乐和音频文件保存在另一个公共位置,依此类推。您的应用可以使用此平台的 MediaStore API 访问此内容。
  • 文档和其他文件: 系统有一个特殊目录,用于包含其他文件类型,例如 PDF 文档和采用 EPUB 格式的图书。您的应用可以使用此平台的存储访问框架访问这些文件。

4.1 媒体内容

Android 10中使用ContentResolver进行文件的增删改查

4.1.2 查询媒体集合

如需查找满足一组特定条件(例如时长为 5 分钟或更长时间)的视频文件,请使用类似于以下代码段中所示的类似 SQL 的选择语句:

data class Video(val uri: Uri,
    val name: String,
    val duration: Int,
    val size: Int
)

val videoList = mutableListOf<Video>()


//媒体数据库列检索
val projection = arrayOf(
    MediaStore.Video.Media._ID,
    MediaStore.Video.Media<
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值