• Android11适配


    1.分区存储

    1.1.背景

    Android 11 进一步增强了平台功能,为外部存储设备上的应用和用户数据提供了更好的保护。作为这项工作的一部分,平台引入了进一步的改进,以简化向分区存储的转换。
    为了让用户更好地控制自己的文件,保护用户隐私数据,并限制文件混乱情况,Android 11在分区存储基础上限制了应用访问其他应用的文件。

    分区存储将存储空间分为两部分:

    ●  公共目录:Downloads、Documents、Pictures 、DCIM、Movies、Music、Ringtones等

        ■ 公共目录的文件在App卸载后,不会删除
        ■ 可以通过SAF、MediaStore接口访问
        ■ 拥有权限,也能通过路径直接访问
    ●  应用专属目录
        ■ 应用专属目录只能自己直接访问
        ■ App卸载,数据会清除。

    1.2兼容影响

    当您将应用更新为以 Android 11 为目标平台后,您将无法使用requestLegacyExternalStorage,而且也没有其他标记可以提供停用分区存储。
    分区存储对于App访问存储方式、App数据存放以及App间数据共享,都产生很大影响。
    而Environment.getExternalStorageDirectory() 在 API Level 29 开始已被弃用,开发者应迁移至 Context#getExternalFilesDir(String), MediaStore, 或Intent#ACTION_OPEN_DOCUMENT。

    1.3 适配

    1.3.1应用targetSdkVersion

    应用targetSdkVersion >= 30,都会强制打开分区存储,同时requestLegacyExternalStorage将会无效。如果您需要对已安装的应用进行适配分区存储的数据迁移,则可以在应用更新到目标平台为Android 11版本后仍暂时保留原有的存储模式。请在应用的manifest中设置preserveLegacyExternalStorage属性为true,应用更新到android 11可以保留存储继承模式。

    1.3.2应用私有目录访问

    对于运行在Android 11的应用,无论targetSdkVersion是什么都无法访问Emulated存储中的其他应用私有目录(Android/data)。SAF(Storage Access Framework)同样也禁止访问应用私有目录。
    某些应用的核心用例需要访问大量的文件,如文件管理操作或备份和恢复操作。这些应用可通过执行以下操作获取“所有文件访问权限”:

    ●  声明 MANAGE_EXTERNAL_STORAGE 权限。
    ●  使用 ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent 操作将用户引导至一个系统设置页面,在该页面上,用户可以为您的应用启用以下选项:授予所有文件的管理权限。

    ●  注意:获得此权限的应用仍然无法访问属于其他应用的应用专用目录。这些目录在存储卷上显示为 Android/data/ 的子目录。

    1.3.3 直接路径访问

    注意:使用直接路径和原生库保存媒体文件时,应用的性能会略有下降。请尽可能改用MediaStore API。

    数据和文件存储概览  |  Android 开发者  |  Android Developers
    Android 11 中的存储机制更新  |  Android 开发者  |  Android Developers

    1.3.4App运行模式

    在Android 11版本上,系统会根据App targetSdkVersion决定运行模式:
    ●  App targetSdkVersion >= 30,默认为分区存储,并且无法取消。

    ●  App targetSdkVersion < 29,默认为分区存储,可通过requestLegacyExternalStorage更改

    应用可以通过AndroidManifest.xml设置requestLegacyExternalStorage, 选择对应的方式:
     


    ●  App targetSdkVersion < 29,声明了READ_EXTERNAL_STORAGE,默认Legacy Mode
    ●  App在下列条件都成立时
       ■  声明 MANAGE_EXTERNAL_STORAGE 权限。
       ■  使用 ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent 操作将用户引导至一个系统设置页面,在该页面上,用户可以为您的应用启用以下选项:授予所有文件的管理权限。
    App拥有外置存储空间Read、Write权限。但是通过Environment.isExternalStorageLegacy接口判断,返回不一定是Legacy Mode。
    判断当前App运行什么模式,可以通过这个API判断:
    Environment.isExternalStorageLegacy() (added in api 29);

    true表示以传统的兼容方式运行,false表示以分区存储运行

    1.3.5 读写公共目录

    App启动分区存储后,只能直接访问自身专属目录,所以Android 11,提供了两种访问公共目录的方法(通过MediaStore定义的Uri、通过SAF接口)

    1.3.5.1. 通过MediaStore定义的Uri
    MediaStore提供了下列几种类型的访问Uri,通过查找对应Uri数据,达到访问的目的。
    下列每种类型又分为三种Uri,Internal、External、可移动存储:

    ●Audio
       ■  Internal: MediaStore.Audio.Media.INTERNAL_CONTENT_URI

           content://media/internal/audio/media。

       ■  External: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI

           content://media/external/audio/media。

       ■  可移动存储: MediaStore.Audio.Media.getContentUri

           content://media//audio/media。
    ●  Video
       ■    Internal: MediaStore.Video.Media.INTERNAL_CONTENT_URI
             content://media/internal/video/media。
       ■    External: MediaStore.Video.Media.EXTERNAL_CONTENT_URI
             content://media/external/video/media。
       ■    可移动存储: MediaStore.Video.Media.getContentUri
             content://media//video/media。
    ●  Image
       ■    Internal: MediaStore.Images.Media.INTERNAL_CONTENT_URI
             content://media/internal/images/media。
       ■    External: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
             content://media/external/images/media。
       ■    可移动存储: MediaStore.Images.Media.getContentUri
             content://media//images/media。
    ●  File
       ■    MediaStore. Files.Media.getContentUri
             content://media//file。
    ●  Downloads
       ■    Internal: MediaStore.Downloads.INTERNAL_CONTENT_URI
             content://media/internal/downloads。
       ■    External: MediaStore.Downloads.EXTERNAL_CONTENT_URI
    content://media/external/downloads。
       ■    可移动存储: MediaStore.Downloads.getContentUri
    content://media//downloads。

    1.3.5.1.1. 获取所有的Volume

    1.3.5.2.通过SAF接口
    SAF,即Storage Access Framework,通过选择不同的DocumentsProvider,提供给用户打开、浏览文件。在Android 11上,无法通过SAF选择外部存储器External Storage根目录、Downloads目录以及App专属目录(Android/data、Android/obb)。

    Android默认提供了下列DocumentsProvider:
    MediaDocumentsProvider、ExternalStorageProvider、 DownloadStorageProvider。
    他们之间差异是:

    1.3.6访问应用的专属目录

    访问应用专属目录分为两种情况,第一是访问App自身专属目录,第二是访问其他App的专属目录。
    1.3.6.1.App自身专属目录
       Android 11获取应用专属目录
       ■  获取Media接口:getExternalMediaDirs
       ■  获取Cache接口:getExternalCacheDirs
       ■  获取Obb接口:getObbDirs
       ■  获取Data接口:getExternalFilesDirs
       应用专属目录App本身可以直接访问。
    1.3.6.2.其他App的专属目录
    Android 11,App无法访问其他App的专属目录(Android/data)。如果需要访问其他应用专属目录数据,需要被访问者按照下列方法来提供:
    1.3.6.2.1.通过SAF文件
    ●  共享App自定义DocumentsProvider
        App自定义DocumentsProvider需要做以下步骤:
        a)指定DocumentsProvider

    1.3.6.2.其他App的专属目录
    Android 11,App无法访问其他App的专属目录(Android/data)。如果需要访问其他应用专属目录数据,需要被访问者按照下列方法来提供:
    1.3.3.2.1.通过SAF文件
    ●  共享App自定义DocumentsProvider
        App自定义DocumentsProvider需要做以下步骤:
        a)指定DocumentsProvider

       b)DocumentsProvider实现基本接口

    ●  访问App通过ACTION_OPEN_DOCUMENT,启动浏览

    1.3.3.2.2.共享App实现FileProvider

    1.3.3.2.3.App自定义私有Provider

    1.3.7.App Scopted Storage,访问权限总结
    App访问不同目录的权限总结如下:

    1.3.8.直接路径访问
    Android 11上,App可以直接通过路径访问拥有权限的文件。例如,可以通过路径访问自己通过MediaStore新建的Images。

    因为现在分区存储公共区域,是基于FUSE来实现,通过直接路径访问会经过下列路程:访问者 →  FUSE →  KERNEL---->MediaProvider(得到真实数据)--->KERNEL →  FUSE→访问者,比之前SDCARDFS多了几个步骤,所以会导致一些性能问题。建议通过MediaStore访问。

    1.3.9.宽泛权限
    Android 11,提供了两种宽泛权限,需要注意的是这两种宽泛权限是无法访问其他应用的专属目录:
    ●  MANAGE_EXTERNAL_STORAGE
        App拥有此权限,能够读写公共区域内所有文件,并且可以访问MediaStore.Files里面的所有文件。此权限能够满足清理、手机搬家、杀毒、文件管理这些类型应用需求。
        App可以通过下列方式申请:

    配置文件中先添加该权限

    ●  System Gallery Role
        Gallery Role只能是预装的系统应用,通过系统配置才能成为Gallery Role。拥有Gallery Role,通过MediaStore读写多媒体文件不用弹框用户交互

    1.3.10.应用卸载
    ●  如果App在AndroidManifest.xml中声明:android:hasFragileUserData="true"
        卸载应用会有提示是否保留App数据:

    ●  App存放到公共目录下的文件,卸载后,如果需要修改,需要用户重新授予权限

    1.3.11.App数据迁移
    App打开分区存储,会涉及到数据的迁移,不然会导致旧数据无法使用。可以从下面几方面着手数据迁移:
    ●  App对于可以存放到公共目录的文件,可以通过MediaStore接口存放到对应类型的公共目录中。
    ●  对于私有数据,可以存放到App私有目录。
    ●  迁移后数据的共享访问
        ■  对于存放到公共目录的文件,其他App可以通过MediaStore访问。
        ■  对于无法存放在公共目录文件,可以放置在私有目录,通过Uri共享给其他App访问。

    1.3.12.MediaStore Queries
    在使用MediaStore进行query动作的时候,使用Projection时,Column Name要在MediaStore中定义好的。

    1.3.13.新建测试使用可移动存储
    如果一个设备没有可移动的存储,可以使用下面的方法新建虚拟存储设备:
    ●  adb shell sm set-virtual-disk true
    ●  在设置 -> 存储 -> Virtual SD,进行初始化

    1.4.规范愿景
    我们希望三方应用,尤其是TOP应用,能够按照分区存储的规范,将用户数据(例如图片、视频、音频等)保存在公共目录,把应用数据保存在SDCARD私有目录,以更好地保护外部存储上的应用和用户数据。而Google正在更新 Google Play 政策,以确保应用只在其真正需要获取位置信息时才请求授权。

    2.1.2应用缓存

    1 背景
    在Android 11上,应用默认不能删除其他应用的缓存文件,即使申请了MANAGE_EXTERNAL_STORAGE权限。
    Google官网特性介绍:
    Android 11 中的存储机制更新  |  Android 开发者  |  Android Developers
    2 兼容性影响
    文件管理类,清理类或其他具有缓存清理功能应用,清除其他应用缓存功能失效。
    3 适配指导
    1 使用intent action - ACTION_MANAGE_STORAGE 检查可用存储空间大小。
    2 如果可用的存储空间不足,使用 intent action —ACTION_CLEAR_APP_CACHE 呈现UI界面让用户确认后,触发所有应用的缓存清理。
    注意:执行 ACTION_CLEAR_APP_CACHE 触发的缓存清理,会清理所有应用的缓存,同时大量的IO操作也会加剧电量消耗,如非必要,请不要使用。

    2.1.3文件访问限制
    1 背景
    如果您的应用以 Android 11 为目标平台并使用存储访问框架 (SAF),则您无法再使用ACTION_OPEN_DOCUMENT和ACTION_OPEN_DOCUMENT_TREE操作访问某些目录,具体限制如下:
    1 访问目录
    您无法再使用ACTION_OPEN_DOCUMENT_TREE 操作来请求访问以下目录:
    Downloads根目录。
    设备制造商认为可靠的各个 SD 卡根目录,无论该卡是模拟卡还是可移除的卡。
    内部存储根目录
    2 访问文件
    您无法再使用 ACTION_OPEN_DOCUMENT_TREE 或 ACTION_OPEN_DOCUMENT操作来请求用户从以下目录中选择单独的文件:
    Android/data/ 目录及其所有子目录。
    Android/obb/ 目录及其所有子目录。

    2 兼容性影响
    如果应用指定AndroidR为运行平台,则不再能使用SAF访问上述指出的目录,可能导致您的业务逻辑异常。
    3 适配指导
    执行以下操作来确认行为变更是否已对应用生效:
    1 将targetSdkVersion指向Android 11
    2 确保已经打开RESTRICT_STORAGE_ACCESS_FRAMEWORK 兼容性开关(使用方法见文档兼容性调试工具部分) 。
    3 使用 intent action - ACTION_OPEN_DOCUMENT_TREE ,检查Downloads目录是否显示并呈灰显状态。
    4 使用intent action - ACTION_OPEN_DOCUMENT检查Android/data/和Android/obb/目录是否都不显示。

    2.1.4存储权限变更
    1 背景
    Android 11 引入了与存储权限相关的以下变更。
    1 不管应用的目标 SDK 版本是什么,以下变更均会在 Android 11 中生效:
    ●  存储运行时权限已重命名为文件和媒体。
    ●  如果应用未选择停用分区存储,并且请求 READ_EXTERNAL_STORAGE 权限,则用户会看到不同于 Android 10 的对话框。该对话框会指示应用正在请求访问相册和多媒体。如下图所示

    在系统设置的设置 > 隐私 > 权限管理器 > 文件和媒体 页面中,用户可以查看已授予权限READ_EXTERNAL_STORAGE应用,应用会列在允许存储所有文件下。
    注意:如果您的应用以Android 11 为目标运行平台,上述允许存储所有文件代表的是对文件的只读权限。

    2 以 Android 11 为目标平台
    如果应用以 Android 11 为目标平台,则WRITE_EXTERNAL_STORAGE 权限和 WRITE_MEDIA_STORAGE 特许权限将不再提供任何其他访问权限。
    2 兼容性影响
    1 存储运行时权限UI发生变更。
    2 WRITE_EXTERNAL_STORAGE 权限和 WRITE_MEDIA_STORAGE 在targetSdkVersion 指定为30时,发生变更。

    2.1.5所有文件访问
    1背景
    有些应用主要功能就是访问手机存储文件,例如文件管理器、备份&恢复出厂操作。在Android 11 版本上,需要通过声明MANAGE_EXTERNAL_STORAGE权限来获取“Allowed for all files(允许存储所有文件)”权限,进行功能实现。
    此权限被授予后,拥有以下权限:
    1.“共享存储”上的所有文件的读写权限
    共享存储说明:
    共享存储空间概览  |  Android 开发者  |  Android Developers
    2. MediaStore.Files表内容
    注意:即便授予了所有文件访问权限,应用也不能获取其他app的应用专属的文件。
    应用专属目录:
    访问应用专属文件  |  Android 开发者  |  Android Developers
    2兼容性影响
    文件管理类应用或其他需要对较多存储文件进行扫描和处理的应用,可能会功能失效。
    3 适配指导
    Google适配指导:
    Android 11 中的存储机制更新  |  Android 开发者  |  Android Developers

    1 AndroidManifest.xml中声明MANAGE_EXTERNAL_STORAGE权限。
    2 使用intent action - ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION 跳转到系统设置页面,引导用户开启“Allowed for all files(允许存储所有文件)”权限。

  • 相关阅读:
    idea自定义 postfix completion提高编码效率
    Pyramid 中的wtforms中的SelectField和通过javascript添加标签选项
    Spring BeanPostProcessor 接口&
    【OAuth2】十八、OIDC的认识应用
    【解决问题】在SpringBoot中通过配置Swagger权限解决Swagger未授权访问漏洞
    深度学习——几种学习类型
    《C++ Core Guidelines解析》:深入理解C++的最佳实践
    你的Web3域名,价值究竟何在?
    理德名人故事:巴菲特传记,“股神”巴菲特的一生
    北斗三号短报文终端露天矿山高边坡监测方案
  • 原文地址:https://blog.csdn.net/qq_33733152/article/details/135482108