最近在适配 Android 10.0的过程中,简单看了下 Android 11的版本变动情况,遇到了一些问题,觉得需要做下整理,这里仅整理 存储机制相关的更新:
一、Android 11中的隐私权
先附上几篇不错的手册文章吧:
说正文,概览如下,这里就挑分区存储主要写一下:
1.存储机制更新
(1)强制执行分区存储
这里先讨论一下,与 Android 10不同的部分。
(1)分区存储允许应用通过 File API 使用文件路径访问文件吗?
我们意识到某些应用会通过代码或程序库直接访问媒体文件路径。因此,在 Android 11 上,拥有可读取外部存储权限的应用,均可在分区存储环境中通过文件路径访问文件。在 Android 10 的设备上,除非在 manifest 中通过主动声明
requestLegacyExternalStorage
属性来选择停用分区存储,否则上述方法是无效的。为了确保不同 Android 版本间的连续性,如果您应用的目标版本是 Android 10 或者是更高版本,您应该选择不启用。(2)与媒体存储 API 相比,文件路径访问的性能表现如何?
性能表现非常依赖具体应用场景。对于像视频播放这样的拥有顺序读取的操作,文件路径访问的性能表现与媒体存储相差无几。但是在随机读写的情境下,采取文件路径的方法最多可慢一倍。为了最快、最稳定的读写,我们推荐您使用 Media Store API。
(3)我的应用需要广泛地访问共享存储,存储访问框架是我唯一的选择吗?
存储访问框架 (简称 "SAF") 用于用户授予对目录和文件的访问权限,但是需要您注意的是,SAF 对某些目录的授权仍存在限制,例如根目录和
Android/data
目录。虽说大多数应用在存储访问时都可以通过我们最佳实践的方式去实现,例如使用 SAF 或媒体存储 API,但在某些应用场景下可能会需要更广泛地访问共享存储,亦或是无法通过最佳实践来有效地访问。针对上述情况,我们增加了MANAGE_EXTERNAL_STORAGE
权限,允许程序访问外部存储上的所有文件 (除了 Android/data 和 Android/obb 目录)。(4)与 Android 10 相比,在 Android 11 上使用 SAF 会有其他限制吗?
目标版本为 Android 11 (API 级别为 30) 并使用 SAF 的应用,将不会被授予某些目录访问权限,例如 SD 卡上的根目录和下载目录。无论是哪个目标 SDK,都无法在 Android 11 上通过存储访问框架访问 Android/data 和 Android/obb 目录。访问 官方文档 了解关于这些限制和测试相关行为的方法。
(5)Data Column 弃用之后,有没有对此功能的其他使用建议?
在 Android 10 上,位于分区存储环境中的应用无法通过文件路径访问文件。为了与这一设计保持一致,我们随后废弃了 DATA column。根据大家的反馈,即需要使用已有的 native 代码或程序库,Android 11 现已支持在分区存储中的应用访问文件路径的功能。相应地,DATA Column 实际上在某些情况下其实是有用的。为了在媒体存储中插入和更新,使用分区存储的应用应使用 DISPLAY_NAME 和 RELATIVE_PATH Column,它们不再需要使用 DATA Column 来完成此功能。当读取磁盘中文件的媒体存储实例时,DATA Column 将具备有效的文件路径,该路径可被文件 API 或 NDK 文件程序库使用。但应用要准备处理任何关于此类操作带来的 I/O 错误,而且不应该假设文件始终是可用的。
(6)在代码或依赖库中如何使用直接文件路径访问文件?
您需要根据运行应用的 Android 版本来整合逻辑。
- 在 Android 11 上运行,使用以下方法:
- 使用 "请求应用权限" 一文中描述的最佳实践来请求 READ_EXTERNAL_STORAGE 权限。
- 使用直接文件路径访问文件。详细信息,请参阅 "使用原始路径访问文件"。
- 在 Android 10 上运行,如果您的应用目标 API 为 Android 10 (API level 29),请停用分区存储并继续使用 Android 9 及更低版本所使用的方法来执行这类操作。
- 在 Android 9 及更低版本上运行,使用以下方法:
- 使用 "请求应用权限" 一文中描述的最佳实践来请求
WRITE_EXTERNAL_STORAGE
权限。- 使用直接文件路径访问文件。
摘自Android 11 开发者常见问题: 存储 | FAQ・第二期
处理媒体文件 (如视频、图片、音频文件) 的一些常见用例,以及应用可以使用的方法,以及每种用例以及其在不同系统版本的实践总结汇总如下。详细步骤可参考: Android 存储空间的最佳实践
好了,下面说正经的,上面看了一堆,可能还是会觉得看的很懵逼,或者说不清,尤其是Android 11又恢复了文件路径访问的方式, 下面写一下我在适配过程中的具体情况和思考,供大家参考:
考虑到适配的省事,而且可以从 Android 9.0及以下直接升级适配到 Android 11.0是最好的,那么我觉得,APP的文件保存位置修改为分区存储,访问方式依旧使用旧版本的文件路径访问(官方更建议使用MediaStore和SAF)是最省事的,以下测试结果围绕这一思路开展。
首先:已将APP的存储位置修改为APP外部私有目录(getExternalFilesDir(),getExternalCacheDir()),图片,视频,音频保存在共享目录(Download、Documents、Pictures 、DCIM、Movies、Music、Ringtones等)。APP外部私有目录即便是在Android 10也可以通过文件路径访问,所以唯一的问题就是共享目录的文件仍然可以使用文件路径访问就可以了。
(1)compileSdkVersion = 30、targetSdkVersion = 30、minSdkVersion = 19,没有设置 android:requestLegacyExternalStorage="true" :
使用文件路径path访问相册图片:Android 11和Android 9设备上可以访问,Android 10设备上无法访问(异常)
我在适配Android 10.0的时候,对于必须要使用文件路径path的地方,采取的方式是:使用ContentResolver和拿到的相册图片Uri,复制图片到私有目录下,然后再使用 文件路径访问,这个操作在该测试条件下,测试 Android 11,10,9设备也都可以
(2)compileSdkVersion = 30、targetSdkVersion = 30、minSdkVersion = 19,设置 android:requestLegacyExternalStorage="true" :
使用文件路径path访问相册图片:Android 11和Android 9设备上可以访问,Android 10设备上也可以
(3)compileSdkVersion = 29、targetSdkVersion = 29、minSdkVersion = 19,没有设置 android:requestLegacyExternalStorage="true" :
因为Android 10共享目录的文件不可以通过 文件路径path访问,所以仅测试我适配时候的方案:
我在适配Android 10.0的时候,对于必须要使用文件路径path的地方,采取的方式是:使用ContentResolver和拿到的相册图片Uri,复制图片到私有目录下,然后再使用 文件路径访问,这个操作在该测试条件下,测试 Android 11,10,9设备也都可以
(4)compileSdkVersion = 29、targetSdkVersion = 29、minSdkVersion = 19,设置 android:requestLegacyExternalStorage="true" :
使用文件路径path访问相册图片:Android 11和Android 9设备上可以访问,Android 10设备上也可以
综上,如果是直接从 Android 9.0以下升级,建议直接适配到Android 11,这样原来那些文件路径访问方式都可以继续使用,只用修改一下APP文件存储位置;如果是 Android 10.0升级适配 Android 11.0可以继续使用 MediaStore 来操作。