Android10
Android 10版本特性
Android 10适配要点,作用域存储
作用域存储,直接颠覆了我们长久以来的外置存储空间的使用方式,因此大量App都将面临着较多代码模块的升级。
理解作用存储
Android 10以前支持外置存储空间这个空间,即SD卡存储。几乎所有App都喜欢在SD卡的根目录下建立一个自己专属的目录,用来存放各类文件和数据。
这样做的好处是:
- 存储在SD卡的文件不会计入到应用程序的占用空间当中;
- 存储在SD卡的文件,即使应用程序被卸载了,这些文件仍被保留下来有助于实现一些数据永久保留的功能。
缺点:
- 导致SD卡空间乱糟糟,卸载应用程序后所产生的垃圾文件扔存在。
- SD卡上的文件属于公有文件,其他应用程序都有权随意访问,导致数据安全性没有保证。
针对上面的问题,Android 10中加入了作用域存储功能。Android 10之后,每个应用程序只能有权在自己的外置存储空间关联目录下读取和创建文件,获取该关联目录的代码context.getExternalFilesDir()
,关联目录对应路径大致如下:
1 | /storage/emulated/0/Android/data/<包名>/files |
这个目录中的文件会被计入到应用程序的占用空间中,会随应用程序卸载而被删除。
访问其他目录(如 读取/存储 相册中的图片)。Android系统针对文件类型进行了分类,图片、音频、视频这三类可通过MediaStore API
进行访问,其他类型的文件需要使用系统的文件选择器来进行访问。
应用程序向媒体库贡献的图片、音频、视频,自动拥有读写权限,不需要额外申请
READ_EXTERNAL_STORAGE
和WRITE_EXTERNAL_STORAGE
权限。应用程序访问其他应用程序向媒体库共享的图片、音频、视频,则必须申请
READ_EXTERNAL_STORAGE
权限才行。WRITE_EXTERNAL_STORAGE
在未来将被废弃。
我们一定要升级吗?
暂时可以不用升级,因为之前传统外置存储空间的用法太广泛了。即项目指定targetSdkVersion
低于 29,即使不做任何作用域存储方面的适配也可以成功运行在Android 10手机上。不过需要在 AndroidManifest.xml
中加入如下配置:
1 | <manifest ...> |
这段配置在Android 11预览版上还不会失效。
针对作用域存储进行适配
本篇文章中演示的所有示例,都可以到ScopedStorageDemo这个开源库中找到其对应的源码
获取相册中的图片
PS 获取音频、适配的用法也基本相同
不同于过去的直接获取到相册中图片的绝对路径,在作用域存储当中,需要借助MediaStore API
获取到图片的Uri
,示例代码:
1 | val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc") |
先通过 ContentResolver 获取到相册中所有图片的id,再借助 ContentUris 将id拼装成一个完整的 Uri 对象。
一张图的 Uri 格式大致如下:
1 content://media/external/images/media/321
图片显示有多种方法,如借助第三方库Glide
1 | Glide.with(context).load(uri).into(imageView) |
不借助第三方库的做法:将Uri对象解析成图片
1 | val fd = contentResolver.openFileDescriptor(uri, "r")//打开文件句柄 |
将图片添加到相册
1 | /** |
1 | /** |
下载文件到Download目录
Android 10上两种解决方式:
第一种较简单,更改文件的下载目录,将文件下载到应用程序关联目录下。这样不改任何代码即可让程序在Android 10上正常工作。缺点:文件会被计入到应用程序的占用空间中,程序被卸载文件也会被删除。
第二种,对Android 10系统进行代码视频,仍将文件下载Download目录下
1 | /** |
与向相册中添加一张图片的过程差不多,Android 10在MediaStore中新增一个 Downloads 稽核,专门用于执行文件下载操作。
主要添加了一些Http请求,并将
MeadiaStore.Images.Media
改成MediaStore.Downloads
使用文件选择器
读取SD卡上非图片、音频、视频类的文件,此时不能用MediaStore API,需用文件选择器。
调用系统内置的文件选择器:
1 | /** |
第三方SDK不支持怎么办
如七牛云SDK,它的文件上传功能要求你传入一个文件的绝对路径,不支持传入Uri对象。
- 由于我们是没有权限修改第三方SDK的,因此最简单直接的办法就是等待第三方SDK的提供者对这部分功能进行更新,在那之前我们先不要将targetSdkVersion指定到29,或者先在AndroidManifest文件中配置一下requestLegacyExternalStorage属性。
- 另一个方法,自己编写一个文件复制功能,将Uri对象所对应的文件复制到应用程序的关联目录下,然后将关联目录下这个文件的绝对路径传递给第三方SDK,即可完美适配
1 | /** |