要在 Google Play 上发布,开发者需要将应用的 目标 API 级别 (targetSdkVersion) 更新到 API 级别 30 (Android 11) 或者更高版本。针对新上架的应用,这个政策自 8 月开始生效;现有应用更新新的版本,这个政策的要求将自 11 月开始生效。

API 30 所带来的一个巨大变更是,应用需要使用分区存储 (Scoped Storage)。

变更之大,对于大型应用来说堪称恐怖。更糟糕的是,我们在网上看到的有关如何适配分区存储的建议,有一些建议十分令人迷惑,甚至会误导我们。

为了帮您排忧解难,我们收集了一些有关分区存储的常见问题,同时也为如何适配您的应用提供了一些建议和可能的替代方案。

Q: android:requestLegacyStorage 会被移除吗?

A: 部分移除。

如果您的应用当前已经设置了 android:requestLegacyStorage=“true”,就应该在 targetSdkVersion 设置为 30 后保持现状。该标记在 Android 11 设备中没有任何效果,但是可以继续让应用在 Android 10 设备上以旧的方式访问存储。

如果您需要针对 Android 10 设备在 AndroidManifest.xml 中设置 android:requestLegacyStorage="true",那在应用的目标版本改为 Android 11 后应当保留此设置。它仍会在 Android 10 设备上生效。

Q: android:preserveLegacyStorage 是如何工作的?

A: 如果您的应用安装在 Android 10 设备上,并设置了 android:requestLegacyStorage="true",那在设备升级至 Android 11 后,此设置会继续保持旧的存储访问方式。

⚠️ 如果应用被卸载,或者是第一次在 Android 11 上安装,那么就无法使用旧的存储访问方式。此标记仅适用于进一步帮助设备从传统存储升级到分区存储。

Q: 如果我的应用没有访问照片、视频或音频文件,是否仍然需要请求 READ_EXTERNAL_STORAGE 权限?

A: 不需要,从 Android 11 开始,仅在访问其他应用所属的媒体文件时才需要请求 READ_EXTERNAL_STORAGE 权限。如果您的应用仅使用自身创建的非媒体文件 (或自身创建的媒体文件),那么就不再需要请求该权限。

如需在 Android 11 后停止请求该权限,仅需修改应用 AndroidManifest.xml 文件中的 <uses-permission> 标签,添加 android:maxSdkVersion=“29” 即可:

<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"android:maxSdkVersion="29" />

Q: 我想要访问不属于我应用的照片、视频或一段音频,我必须使用系统文件选择器吗?

A: 不。但如果您想用就可以用,ACTION_OPEN_DOCUMENT 最早可支持至 Android KitKat (API 19),而 ACTION_GET_CONTENT 则支持至 API 1,二者使用的都是系统文件选择器。由于不需要任何权限,这仍然是首选的解决方案。

如果您不想使用系统文件选择器,您仍然可以请求 READ_EXTERNAL_STORAGE 权限,它会使您的应用可以访问所有的照片、视频以及音频文件,同时也包含访问 File API 的权限!

如果您需要使用 File API 访问媒体内容,记得设置 android:requestLegacyStorage="true",否则 File API 在 Android 10 中将无法工作。

Q: 我想保存非媒体文件,但我不想在卸载我的应用时删除它们。我需要使用 SAF 吗?

A: 也许需要。

如果这些文件允许在应用外打开而无需通过您的应用,那么系统文件选择器是较好的选择。您可以使用 ACTION_CREATE_DOCUMENT 创建文件。当然也可以使用 ACTION_OPEN_DOCUMENT 来打开一个现有文件。

如果应用曾经创建了一个目录用于存储所有这些文件,那最好的选择就是使用系统文件选择器和 ACTION_OPEN_DOCUMENT_TREE,以便用户可以选择要使用的特定文件夹。

如果这些文件只对您的应用有意义,可以考虑在应用 AndroidManifest.xml 文件的 <application> 标签中设置 android:hasFragileUserData="true"。这将使用户可以保留这些数据,即使在卸载应用时亦是如此。

△ 上图为拥有 “脆弱用户数据” 应用的卸载对话框。对话框中包含了一个复选框,用于指示系统是否应该保留应用数据。

设置了该标记后,存储文件的最佳位置将取决于其内容。包含敏感或私人信息的文件应当存储在 Context#getFilesDir() 所返回的目录中;而不敏感的数据则应存储于 Context#getExternalFilesDir() 所返回的目录中。

Q: 我可以将非媒体文件放置于其他文件夹中 (例如 Downloads 文件夹),而无需任何权限。这是一个 Bug 吗?

A: 不是。应用可能会向这类集合提供文件,而且最好的方式是对非媒体文件同时使用 Downloads 和 Documents 集合。不过请记得,默认情况下只有创建该文件的应用才可以访问它们。其他应用需要通过系统文件选择器获得访问权限或者拥有对外部存储的广泛访问权限 (即: MANAGE_EXTERNAL_STORAGE 权限) 才行。

⚠️ 对 MANAGE_EXTERNAL_STORAGE 权限的访问受到 Play 政策 监管。

Q: 如果我需要保存一个文档,是否需要使用 SAF?

A: 不用。应用可以向 Documents 与 Downloads 集合提供非媒体文件,而无需任何特殊权限。只要没被卸载,那么向这些集合提供文档的应用拥有这些文档的完全访问权限。

Android 分区存储常见问题解答相关推荐

  1. 【错误记录】Android 分区存储 错误 ( 文件格式不匹配 )

    文章目录 一.报错信息 二.解决方案 一.报错信息 Android 分区存储 , 将 图片文件 保存到 Movies 目录下报错 : 2021-05-18 14:31:50.691 1341-5448 ...

  2. Android分区存储

    1.分区存储概述 分区存储是Android 10开始引进的Android系统存储管理机制,它允许App读取和写入App自身创建的文件而不需要任何存储权限.其中根据存储位置的不同,可以分为内部内部存储和 ...

  3. android 分区存储适配总结

    android 分区存储适配总结 一.分区存储概念 二.分区适配方案 1. 应用分区存储的文件访问规定 (1).应用专属目录 (2).共享目录文件 2.MediaStore API介绍 3.Stora ...

  4. 强制开启Android 分区存储 沙盘文件系统

    为了测试Android 11下强制分区存储后的应用兼容问题,这里摸索了下目前的打开方式 1. 在AS里下载API 30的 虚拟机 2. 打开虚拟机,进入首页后,执行 adb shell sm set- ...

  5. 【错误记录】Android 分区存储下的 SD 卡应用专属外部存储空间目录访问 ( 需手动创建应用专属外部存储空间目录 )

    文章目录 一.报错信息 二.解决方案 一.报错信息 开发时 , 需要向外置 SD 卡中拷贝一些文件 , 应用读取这些文件 , 进行相关配置 ; 但是 Android 系统 , 并不会主动为应用创建文件 ...

  6. 【Android 文件管理】分区存储 ( 修改与删除图片文件 )

    文章目录 一.分区存储模式下使用 MediaStore 修改图片 二.分区存储模式下使用 MediaStore 删除图片 三.相关文档资料 Android 分区存储系列博客 : [Android 文件 ...

  7. 【Android 文件管理】分区存储 ( 创建与查询图片文件 )

    文章目录 一.分区存储模式下使用 MediaStore 插入图片 二.分区存储模式下使用 MediaStore 查询图片 三.相关文档资料 Android 分区存储系列博客 : [Android 文件 ...

  8. Android11(30)/Android10(29)分区存储-存储访问框架(SAF)

    概述 存储访问框架(SAF)是在Android 4.4(API 级别 19)引入的.借助 SAF,用户可轻松打开文档.图像及其他文件. 存储访问框架包含三部分: 文档提供程序 - 文档提供程序以 Do ...

  9. 结合Android去水印APP谈谈分区存储

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 前言 方便个人更新微信状态,上周花半天时间编写简单的抖音去水印AP ...

最新文章

  1. 25岁Nature狂魔八连杀!曹原再次“一作+通讯”发Nature!
  2. Eclipse执行import命令导入maven项目时报错:Add a version or custom suffix using Name template in Advanced set...
  3. c#屏幕录制(经典)(含源码和AForge.Video.FFMPEG.DLL)及填坑办法
  4. [转]那些相见恨晚的 JavaScript 技巧
  5. matlab向量相减代码,matlab转c++代码实现(主要包含C++ std::vector,std::pair学习,包含数组与常数相乘,数组相加减,将数组拉成一维向量等内容)...
  6. 线段树线段树的创建线段树的查询单节点更新区间更新
  7. Python数据分析之pandas常用命令整理!
  8. 奎享添加自己字体_奎享雕刻软件写字操作简要说明
  9. c语言用数字定义字符串,c语言怎么定义数字字符串 c语言怎么把数字字符定义字符串...
  10. lpad()函数oracle,oracle 中lpad的用法
  11. 什么是深拷贝与浅拷贝
  12. 201871010126 王亚涛 《面向对象程序设计(java)》 第四周学习总结
  13. 永远的疯狂竹子----纪念退役不久的V-Gundam
  14. 数据结构与算法 — 约瑟夫问题(Josephu)
  15. matlab运动控制,运动控制MATLAB仿真.doc
  16. 软件测试就是找茬的?那些年和开发小哥的“爱恨情仇”
  17. 个人总结出来的git仓库迁移方案
  18. FCN(全卷积神经网络)
  19. 代驾小程序开发有哪些功能
  20. 适用mini SD卡的手机

热门文章

  1. AfxMessageBox用法
  2. sqlserver查询字段string转数组
  3. Latex论文模板修改目录页的生成内容
  4. C++13:搜索二叉树
  5. (学习笔记)Python3网络爬虫(三):漫画下载,动态加载、反爬虫这都不叫事!
  6. 洗地机什么牌子最好?洗地机测评排行榜
  7. 永洪科技:BI+AI打造BI界的“ChatGPT”
  8. Xcode Command Line Tools命令
  9. JavaScript 合并数组
  10. Cloudera Manager的安装