android Q 存储权限和行为变更

分区存储

在Android Q中引入了分区储存功能,在外部存储设备中为每个应用提供了一个“隔离存储沙盒”。
其他应用无法直接访问应用的沙盒文件。由于文件是应用的私有文件,不再需要任何权限即可访问和保存自己的文件。
此变更并有助于减少应用所需的权限数量,同时保证用户文件的隐私性。

权限变更

	Android Q 更改了应用对设备外部存储设备中的文件(如:/sdcard )的访问方式。
	继续使用 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限,
	只不过当拥有这些权限的时候,你只能访问媒体文件,无法访问其他文件。
	
	在早先的beta版本中,Android需要申请特定的媒体权限 :READ_MEDIA_IMAGES, READ_MEDIA_VIDEO , 
	READ_MEDIA_AUDIO, 但是在beta4中,这些权限被废弃。

访问私有文件

应用需要将文件存储在应用的沙盒中,并且访问这个文件夹无需权限。
官方推荐应用在沙盒内存储文件的地址为Context.getExternalFilesDir()下的文件夹。
比如要获得一张图片

Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)

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

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

SAF 包含以下内容:

文档提供程序 —

一种内容提供程序,可让存储服务(如 Google Drive)显示其管理的文件。
文档提供程序以 DocumentsProvider 类的子类形式实现。文档提供程序的架构基于传统的文件层次结构,
但其实际的数据存储方式由您决定。Android 平台包含若干内置文档提供程序,
如 Downloads、Images 和 Videos。

客户端应用 —

一种自定义应用,它会调用 ACTION_OPEN_DOCUMENT 和/或 ACTION_CREATE_DOCUMENT Intent
 并接收文档提供程序返回的文件。

选择器 —

 一种系统界面,可让用户访问所有满足客户端应用搜索条件的文档提供程序内的文档。

以下为 SAF 提供的部分功能:

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

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

1、 您的应用已获得 READ_EXTERNAL_STORAGE 权限。
2、这些文件位于以下其中一个明确定义的媒体集合中:

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

任何其他文件(包括“downloads”目录下的文件),必须使用https://developer.android.google.cn/guide/topics/providers/document-provider

分区存储
在Android Q设备上有两种方式来让分区存储生效:

以 Android 9 或更低版本为目标平台 (Target SDK <=28)
如果Target SDK > 28,请在manifest中添加android:requestLegacyExternalStorage=“true”

这样就可以采用原有的存储策略。以上方式不建议使用。
目前官方提示,宣布将在Android Q的最终版本中提供兼容性模式。这意味着,谷歌至少要到Android R上才会完整地启用这一模式。不过,目标API为Android Q(API级别29)的应用,仍然需要采用这套全新的机制。

文件访问权限摘要
在这里插入图片描述

1.用户存储权限的变更

  1. 访问自己文件:

     Q中用更精细的媒体特定权限替换并取消了 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE权限,
     并且无需特定权限,应用即可访问自己沙盒中的文件。
    
  2. 访问系统媒体文件:

     Q中引入了一个新定义媒体文件的共享集合,如果要访问沙盒外的媒体共享文件,比如照片,音乐,视频等,
     需要申请新的媒体限:READ_MEDIA_IMAGES,READ_MEDIA_VIDEO,READ_MEDIA_AUDIO,申请方法同原来的存储权限。
    
  3. 访问系统下载文件:

     对于系统下载文件夹的访问,暂时没做限制,但是,要访问其中其他应用的文件,
     必须允许用户使用系统的文件选择器应用来选择文件。
    

请判断当应用运行在Q平台上时,取消对READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE两个权限的申请。并替换为新的媒体特定权限。

当满足以下每个条件时,将开启兼容模式,即不开启Q设备中的存储权限改动:

应用targetSDK<=P。

应用安装在从 Android P 升级到 Android Q 的设备上。

但是当应用重新安装(更新)时,不会重新开启兼容模式,存储权限改动将生效。

所以按官方文档所说,无论targetSDK是否为Q,必须对应用进行存储权限改动的适配。

在测试中,当targetSDK<=P,在Q Beat1版上申请两个旧权限时会自动改成申请三个新权限,不会影响应用正常使用,但当targetSDK==Q时,申请旧权限将失败并影响应用正常使用。

2.用户的定位权限的变更

为了让用户更好地控制应用对位置信息的访问权限,Android Q 引入了新的位置权限 ACCESS_BACKGROUND_LOCATION。

与现有的 ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION 权限不同,新权限仅会影响应用在后台运行时对位置信息的访问权。除非应用的某个 Activity 可见或应用正在运行前台服务,否则应用将被视为在后台运行。

与iOS系统一样,Q中也加入了后台位置权限ACCESS_BACKGROUND_LOCATION,如果应用需要在后台时也获得用户位置(比如滴滴),就需要动态申请ACCESS_BACKGROUND_LOCATION权限。

当然如果不需要的话,应用就无需任何改动,且谷歌会按照应用的targetSDK作出不同处理:

targetSDK <= P 应用如果请求了ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION权限,Q设备会自动帮你申请ACCESS_BACKGROUND_LOCATION权限。

设备唯一标识符

从 Android Q 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 签名权限才能访问设备的不可重置标识符(包含 IMEI 和序列号)。

许多用例不需要不可重置的设备标识符。如果您的应用没有该权限,但您仍尝试查询标识符的相关信息。会返回空值或报错。

设备唯一标识符需要特别注意,原来的READ_PHONE_STATE权限已经不能获得IMEI和序列号,如果想在Q设备上通过

((TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()

获得设备ID,会返回空值(targetSDK<=P)或者报错(targetSDK==Q)。且官方所说的READ_PRIVILEGED_PHONE_STATE权限只提供给系统app,所以这个方法算是废了。

谷歌官方给予了设备唯一ID最佳做法,但是此方法给出的ID可变,可以按照具体需求具体解决。

本文给出一个不变和基本不重复的UUID方法。

public static String getUUID() {

String serial = null;

String m_szDevIDShort = "35" +
        Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +

        Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 +

        Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 +

        Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 +

        Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 +

        Build.TAGS.length() % 10 + Build.TYPE.length() % 10 +

        Build.USER.length() % 10; //13 位

try {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        serial = android.os.Build.getSerial();
    } else {
        serial = Build.SERIAL;
    }
    //API>=9 使用serial号
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
} catch (Exception exception) {
    //serial需要一个初始化
    serial = "serial"; // 随便一个初始化
}
    //使用硬件信息拼凑出来的15位号码
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

虽然由于唯一标识符权限的更改会导致android.os.Build.getSerial()返回unknown,但是由于m_szDevIDShort是由硬件信息拼出来的,所以仍然保证了UUID的唯一性和持久性。

minSDK警告

在 Android Q 中,当用户首次运行以 Android 6.0(API 级别 23)以下的版本为目标平台的任何应用时,Android平台会向用户发出警告。

如果此应用要求用户授予权限,则系统会先向用户提供调整应用权限的机会,然后才会允许此应用首次运行。

谷歌要求运行在Q设备上的应用targetSDK>=23,不然会向用户发出警告。

存储访问框架官方地址:https://developer.android.google.cn/guide/topics/providers/document-provider

由于还未来得及对存储访问框架进行实验,目前采用了规避沙盒机制的命令:
adb shell sm set-isolated-storage off

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值