欢迎光临
专注android技术,聚焦行业精粹,我们一直在努力

Android Q 隐私变化: 分区域存储

从Android Q Beta 3开始,针对Android 9(API级别28)或更低版本的应用程序默认情况下看不到以前Android版本的存储工作方式。当您更新现有应用以使用分区域存储时,即使您的应用的targetSdkVersion是Android 9或更低版本,您也可以使用新的清单属性在Android Q设备上启用应用的新行为。

为了能给用户提供对文件的更多控制并限制文件混乱,Android Q改变了应用程序访问设备外部存储上文件的方式,例如存储在路径/ sdcard中的文件。Android Q继续使用READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE权限,这些权限对应于存储面向用户的运行时权限。但是,默认情况下targetSdkVersion设置为Android Q的应用(以及manifest清单开启属性来启动这个变更的应用)会获得一个沙盒视图到外部存储。此类应用程序只能看到其特定于应用程序的目录和特定媒体类型,因此应用程序不需要请求任何其他用户权限。

注意: 早期测试版本中引入的专门用于操作媒体文件的权限 – READ_MEDIA_IMAGESREAD_MEDIA_AUDIOREAD_MEDIA_VIDEO – 现已过时。

本指南介绍了沙盒视图中的文件,以及如何更新应用程序以便它可以继续共享,访问和修改保存在外部存储设备上的文件。本指南还介绍了与照片中的位置信息,如何用代码实现访问媒体以及如何通过列名查询ContentProvider的使用相关的几个注意事项。

 

1、在外部存储上创建文件的改进

除了引入分区存储隐私行为更改之外,Android Q还提供了更多写文件的灵活性,并引入了一些功能,可帮助您修改这些文件在外部存储设备上保存的位置。

1.1、新媒体文件的Pending状态

Android Q引入了IS_PENDING标志,该标志为您的应用提供了在写入磁盘时对媒体文件的独占访问权限。

以下代码段展示了在应用中创建新图片时如何使用IS_PENDING标记:

1.2、对存储位置的影响

Android Q引入了多种功能,可帮助您整理应用为在部存储存放的文件。

1.2.1、目录提示

当您的应用在运行Android Q的设备上创建媒体时,默认情况下会根据媒体类型对媒体进行整理。 例如,默认情况下,新图像文件放在“pictures”目录中。

如果您的应用程序需要指定文件存储的特定位置(例如pictures/MyVacationPictures),则可以设置MediaColumns.RELATIVE_PATH以向系统提供存储新写入文件的位置的提示。 同样,您可以在调用update()方法时通过更改MediaColumns.RELATIVE_PATHMediaColumns.DISPLAY_NAME来移动磁盘上的文件。

1.2.2、设备选择

在Android 9(API级别28)及更低版本中,保存到外部存储设备的所有文件都显示在名为external的单个卷下。然而,Android Q为每个外部存储设备提供唯一的卷名。 这个新的命名系统可以帮助您有效地组织和索引内容,并使您可以控制新内容的存储位置。

主共享存储设备始终称为VOLUME_EXTERNAL。 您可以通过调用MediaStore.getAllVolumeNames()来发现其他卷。

如果要进行查询,插入,更新或删除特定卷里面的内容,请将卷名称传递给MediaStore API中可用的任何getContentUri()方法,例如,在以下代码段中:

警告:在Android Q中已经废弃使用StorageVolume类中的createAccessIntent()方法,因此不应使用此方法浏览外部存储设备。 如果您这样做,运行Android Q设备的用户将无法在您的应用中查看保存在外部存储中的文件。

2、外部存储中的文件的筛选视图

注意:在早期的beta版本中,这个文件到外部存储的视图被称为沙盒视图。

默认情况下,如果您的应用的targetsdkversion设置为Android Q,则它具有外部存储设备上的文件的筛选视图。 该应用程序可以使用Context.getExternalFilesDir()在特定于应用程序的目录下存储用于自身的文件。

具有筛选视图的应用程序始终可以访问其创建的文件,包括其特定于应用程序的目录内部和外部。您的应用程序不需要声明任何存储权限即可访问这些文件。

只有在以下两个条件均为满足时,您的应用程序才能访问其他应用程序创建的文件:

1、您的应用程序已被授予READ_EXTERNAL_STORAGE权限。

2、文件位于以下定义良好的媒体集合之一:

  • 照片,存储在MediaStore.Images中。
  • 视频,存储在MediaStore.Video中。
  • 音乐文件,存储在MediaStore.Audio中。

为了访问另一个应用程序创建的任何其他文件,包括“downloads”目录中的文件,您的应用程序必须使用存储访问框架,该框架允许用户选择特定文件。

注意:对外部存储具有筛选视图的应用程序没有对路径的直接的内核访问权限,例如/sdcard/dcim/img1024.jpg。要访问此类文件,应用程序必须使用MediaStore,调用openFile()等方法。

筛选后的视图还施加了以下与媒体相关的数据限制:

  • 图像文件中的exif元数据已被修改,除非您的应用程序已被授予ACCESS_MEDIA_LOCATION的权限。在“如何访问图片中的位置信息”部分了解更多信息。
  • Media store数据库里面每个文件的DATA列的值也是被修改过的
  • MediaStore.Files表本身已经被筛选过了,只显示照片、视频和音频文件。例如,此表不再显示PDF文件。

想要使用代码来访问媒体文件,需要通过你java或kotlin语言的MediaStore来获取文件,然后传递对应的descriptor到你的代码里。有关详细信息,请参阅有关如何从本机代码访问媒体文件的部分。

若要访问本机代码中的媒体文件,请使用基于MediaStor的基于Java或KOTLIN的代码检索文件,然后将相应的文件描述符传递到本机代码中。有关详细信息,请参阅有关如何使用代码访问媒体文件的部分。

2.1、存储访问框架概览

Android 4.4(API 级别 19)引入了存储访问框架 (SAF)。SAF 让用户能够在其所有首选文档存储提供程序中方便地浏览并打开文档、图像以及其他文件。 用户可以通过易用的标准 UI,以统一方式在所有应用和提供程序中浏览文件和访问最近使用的文件。

云存储服务或本地存储服务可以通过实现封装其服务的 DocumentsProvider 参与此生态系统。只需几行代码,便可将需要访问提供程序文档的客户端应用与 SAF 集成。

SAF 包括以下内容:

  • 文档提供程序 — 一种内容提供程序,允许存储服务(如 Google Drive)显示其管理的文件。 文档提供程序作为DocumentsProvider 类的子类实现。文档提供程序的架构基于传统文件层次结构,但其实际数据存储方式由您决定。Android 平台包括若干内置文档提供程序,如 Downloads、Images 和 Videos。
  • 客户端应用 — 一种自定义应用,它调用 ACTION_OPEN_DOCUMENT 和/或 ACTION_CREATE_DOCUMENT Intent 并接收文档提供程序返回的文件;
  • 选取器 — 一种系统 UI,允许用户访问所有满足客户端应用搜索条件的文档提供程序内的文档。

SAF 提供的部分功能如下:

  • 允许用户浏览所有文档提供程序而不仅仅是单个应用中的内容;
  • 让您的应用获得对文档提供程序所拥有文档的长期、持久性访问权限。 用户可以通过此访问权限添加、编辑、保存和删除提供程序上的文件;
  • 支持多个用户帐户和临时根目录,如只有在插入驱动器后才会出现的 USB 存储提供程序。

简单的说就是如果您的应用想要访问其它应用创建的在非公共目录下面的文件时,需要用户的介入和授权才能操作

3、卸载后保留应用程序的文件

如果某个应用程序在外部存储中具有已筛选的视图,然后卸载该应用程序,应用程序特定目录中的所有文件将会被清除。要在卸载后保留这些文件,请将其保存到MediaStore中的目录中。

3.1、关闭筛选视图

警告:在明年的主要系统版本中,所有应用程序都需要支持区域存储,与targetsdkversion级别无关。因此,您应该提前确保您的应用程序能够很好地使用区域存储。为此,请确保在运行应用程序的Android Q设备上启用该行为。

大多数已经遵循Android存储最佳实践的应用程序可以在进行最小的更改后就可以与区域存储一起工作了。在应用程序还没有完全做好兼容适配或测试之前,您可以通过设置你的targetsdkversion的版本或者新的manifest属性requestLegacyExternalStorage临时关闭区域存储的行为:

  • targetsdkversion版本设置为Android 9 (API level 28) 或更低
  • 如果您的应用的targetsdkversion是Android Q, 也可以在您的应用的manifest文件里面设置requestLegacyExternalStorage的值为true(如果您的targetsdkversion为Q时,这个值默认为false)

注意:为了测试当targetsdkversion 为Android 9或更低版本的应用程序对区域存储的兼容情况,可以通过将requestlegacyexternalstorage的值设置为false来启用该行为。

3.2、设置虚拟外部存储设备

在没有可移动外部存储的设备上,使用以下命令启用虚拟磁盘以进行测试:

3.3、筛选视图文件访问摘要

下表总结了在外部存储中拥有筛选视图的应用程序访问文件的限制:

文件位置 需要的权限 访问需要使用的API方法 App卸载后文件是否删除?
App特定的目录 getExternalFilesDir()
Media 文件集
(photos, videos, audio)
READ_EXTERNAL_STORAGE
仅当访问其它应用的文件时需要
MediaStore
Downloads
(文档和电子书等)
Storage Access Framework
(使用系统的文件选择器)

*你也可以使用 Storage Access Framework 来访问上面表格里面所有列出的位置中的文件,并且不要申请任何权限。

 

4、推荐的几种文件操作的方式

当您的应用的targetsdkversion为 Android Q 时,这一节的内容对基于媒体的几种应用类别,提供了如何适配AndroidQ中这些存储行为的变更的一些建议和方法。

这是一个最好的使用筛选视图的实践,除非您的应用访问的文件不在外部存储的应用特定目录或者MediaStore

4.1、分享媒体文件

有些应用程序允许用户彼此共享媒体文件。例如,社交媒体应用程序允许用户与朋友共享照片和视频。

要访问用户想要共享的媒体文件,请使用MediaStore API。您可以使用这个相同的API来存储用户通过应用程序接收到的任何文件。

4.2、如何操作文档文件

一些应用程序是基于文档集合的,在这些应用程序里面用户可以与小伙伴共享文档集合,或者将文档导入到其它文件集合里面。常见的几个例子包括用户打开一个商业文档或打开一本保存为epub文件的电子书。

在这些场景中,系统允许用户通过ACTION_OPEN_DOCUMENT intent来选择需要打开的文件,这个intent将会打开系统的文件选择器应用。同时为了只展示您应用支持的文件类型,您可以在您的intent里面添加Intent.EXTRA_MIME_TYPES附加数据。

Github上的ActionOpenDocument示例演示了如何在获得用户同意后使用ACTION_OPEN_DOCUMENT打开文件。

4.3、文件组管理

文件管理和媒体创建应用程序通常管理目录层次结构中的文件组。这些应用程序可以调用ACTION_OPEN_DOCUMENT_TREE 的intent,以允许用户授予对整个目录树的访问权限。这样的应用程序能够编辑所选目录中的任何文件,以及它的任何子目录。

使用这个接口,用户也可以访问任何DocumentsProvider提供的文件,DocumentsProvider可以支持任何本地的文件或基于云的解决方案。

GitHub的 ActionOpenDocumentTree 示例展示了如何使用ACTION_OPEN_DOCUMENT_TREE在获得用户授权后打开一个目录树。

注意:当使用ACTION_OPEN_DOCUMENT_TREE时,您的应用程序只获得了用户选择的目录里面所有所有文件的访问权限。您没有访问此用户选择的目录之外的其他应用程序文件的权限。它是基于用户控制访问的,允许用户准确选择他们愿意与您的应用程序共享的内容。

5、访问和编辑媒体内容

本节提供在外部存储中加载和存储媒体文件的最佳实践,以便您的应用程序继续在Android Q中提供良好的用户体验。

注意:如果一个应用在外部存储有筛选视图,并且申请了存储的运行时权限,这个应用程序可以访问在系统特定于该应用程序的目录里面的文件,或者下面列出的下列媒体集合之一:

即使这个应用拥有存储的权限,这个应用如果想要访问外部存储设备的原始文件系统也只能访问应用自己包名路径下面的私有目录。如果应用程序想要使用原始文件系统视图(原始文件路径)来访问该应用程序包名目录以外的文件,将会收到下面的错误:

5.1、访问文件

不要再使用已过期的DATA 列来加载文件。相反,可以使用ContentResolver的下面方法:

注意: 您可以通过调用MediaStore.setIncludePending()来获取Pending状态的文件集合。

以下代码段显示了如何访问媒体文件(官方只提供了Kotlin代码):

5.1.2、通过代码访问文件描述符

以下代码段显示了如何将媒体对象的文件描述符传递到应用程序的本机代码中:

5.2、更新其他应用程序的媒体文件

注:预计以下行为将在Android Q的未来测试版中生效。

修改另一个应用程序最初保存到外部存储设备的指定媒体文件,需要catch系统抛出的RecoverableSecurityException 异常。然后你可以请求用户授权您的app对指定文件项的访问权限。

5.3、图片中的位置信息

一些照片在其exif的metadata数据中包含位置信息,可以让用户看到这个照片拍摄的位置信息。由于这个位置信息是敏感信息,Android Q会默认对应用程序在筛选视图访问手机外部存储时隐藏这些信息。这种对位置信息的限制不同于适用于摄像机特性的限制

如果应用程序需要访问照片的位置信息,请完成以下步骤:

  1. 添加新的ACCESS_MEDIA_LOCATION权限到您的应用的manifest文件
  2. 通过您的MediaStore 对象,调用setRequireOriginal()方法,并传递照片的URI

该过程的代码示例如下:

 

6、Content 查询中的列名

如果您的应用需要用到查询并用到数据库列名,例如:查询mime_type列来获得MimeType,请记住Android Q里面获取列名要通过定义在MediaStore API里面列名来获取。

如果您的代码依赖于需要在Android API中未定义的列名的库,例如MimeType,请使用CursorWrapper在应用程序进程中动态转换列名。

 

赞(0) 打赏
未经允许不得转载:花花鞋 » Android Q 隐私变化: 分区域存储
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

国内精品Android技术社区

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏