最近(大概4月中旬)收到华为市场官方的邮件,要求APP端能在五月底之前适配完最新的Android Q系统.在这个时间段内穿插了两个项目需求版本,Android Q
的版本也从Bate1
升级到了Bate3
.
Android Q版本的更新还是相当大的,在Bate1
版本如果未适配.即使在targetSdkVersion
不是Q的情况下,可能应用程序依然不能正常运行.可能是考虑这个操作过于激进,最新的Bate3
版本把外部存储沙箱化的过程,继续往后延迟一个版本Android至11.大概就是要留出一个版本时间让大家进行适配.
在浏览华为官方给出的适配指导文档以及Android官方的Android Q版本介绍后,大概有一下几个比较重要的改动:
存储权限(外部存储的沙箱化与iOS一样的体验)
在Bate1版本中,Google官方文档说明,沙盒化是必然在Q版本生效的
可以使用adb shell sm set-isolated-storage on
打开系统的全局沙箱化,并表示在后续的版本中会逐渐默认开启.对于从低版本升级到Q的系统,如果APP的目标平台低于Q,则默认不会沙箱化该APP,但是一旦重装就会受到这个约束.
不过在Bate3中又做了改动,沙箱化的改动不再是全局直接生效,而是针对每个APP的在清单文件中,通过<application android:allowExternalStorageSandbox = “false” ... >
这个字段配置生效,其中如果TargetSDKVersion是Q的话,那么这个值默认是true.(在官方文档中表示这个"allowExternalStorageSandbox"关键字只是暂定的,可能后续会改动).
针对没有外部存储的设备,如果想要做测试的话,可以使用adb shell sm set-virtual-disk true
指令设置虚拟磁盘测试.
沙箱化生效后,针对APP访问外部存储就大致分了三个部分.
1.访问自己沙箱内的文件
无需任何权限.自己沙箱的目录地址是
Context.getExternalFilesDir()
,如果想要保存一张图片,那么他的地址目录,应该是:Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
.其中访问自己沙箱内的文件,依然可以使用Java的File系统.直接使用路径名.但是如果不是自己沙箱内的文件,返回的文件路径将不能直接使用.
2.访问外部的公共多媒体文件
在
Bate1
版本中,Google新增了三个权限READ_MEDIA_IMAGES,READ_MEDIA_VIDEO,READ_MEDIA_AUDIO
表示访问media的权限,取代了之前的READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE
.兼容的话,老版本后者的权限会在Q平台默认转换成前三个新权限.针对后三个新权限,其中读取Images和Video是一体的,申请一个通过,那么另一个也白给.对于多媒体文件,一个APP只能写入或者删除自己插入的文件,其他APP插入的,不能修改.除非APP本身是系统默认应用.比如APP是默认图库,那么他可以删除或者修改其他APP插入的图片.如果有修改其他APP多媒体文件的需求,要有限申请默认的角色权限.
不过在
Bate3
版本,google又退回了原来的权限.整体上就是使用MediaStore的API做多媒体文件的访问.3.访问外部的下载文件
Google在4.4版本就已经 有一套Storage Access Framework(
SAF
) 的 DocumentFile API 进行读写.通过这种形式还可以持续获得某个文件夹的读取权限.google说明使用SAF的API可以读取上边三种存储,而不需要任何权限.
4.访问其他APP的沙箱文件
类似于分享功能,如果我们需要分享一张自己的沙箱内的图片,到微信或者其他平台.那么因为沙箱的问题,会造成该文件无法找到.这个解决方案类似于Android7.0上的FileUriExposedException,需要使用V4包提供的FileProvider,将file的传递转换为content的传递,然后同时赋予暂时的读权限.分享的功能,我们使用的是SDK,据观察微信的分享SDK用的就是FileProvider的形式.
以上就是Android Q关于外部存储的改动,还有诸多细节以及新的特性没有一一列出,毕竟我们主要是想APP的正常运行,这部分对于我们APP的影响,需要检查的位置主要有:
1.分享 2.修改头像时图片选择 3.上传评价时图片的选择 4.将海报存储到本地相册.
设备唯一标识符
AndroidQ中去掉了READ_PHONE_STATE
权限,取而代之的是一个系统级别的权限:READ_PRIVILEGED_PHONE_STATE
,所以Android Q平台无论如何也不会再有IMEI和序列号SerialNumber
1.对于目标平台<Q并且没有申请READ_PHONE_STATE
权限,或者目标平台>=Q,尝试获取DeviceId或抛出SecurityException.
2.对于目标平台<Q并且申请READ_PHONE_STATE
权限,那么读取deviceId(IMEI)为null.
3.通过Build.getSerial()获取到的值会是unknown.
针对这个变化,需要重新整理APP内生成设备唯一Id的方法:Google官方的指导方法,不过这个方法可能同一设备不唯一.ANDROID_ID的获取一直不受影响. 不过这个值可能因为手机厂商的设置导致不可用.不过设备唯一Id一直也没有100%的解决方案,可以根据实际情况定夺.
后台定位权限
Android Q中新增了后台定位权限ACCESS_BACKGROUND_LOCATION
,之前的ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION
则表示用户请求前台定位权限.那么Android的定位权限对话框就表现的iOS一致.
其中对于老版本,申请了
ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION
后,系统会默认帮你申请ACCESS_BACKGROUND_LOCATION
,即对话框所示.PS:如果用户拒绝了后台定位,那么就只能通过启动前台服务来进行前台定位.而且前台服务目标需要设置为locaiton.
foregroundServiceType=“location”
事实上,根据适配指导,Android Q的后台定位会有比较大的限制,大概30m一次,如果是导航,启动前台服务依然是必须的.PPS:AndroidQ这里对于应用前台的定义就是有没有可见的Activity或者前台service.这一点与Android O中,后台启动服务的后台又有不一样.具体可以参考Android 8.0后台启动服务.
我们的APP其实对于定位不需要做任何改动.因为不需要后台定位权限.
禁止应用后台弹页面
AndroidQ在开发者选项中:关闭允许系统执行后台活动开发者选项即可启用限制.只能通过用户的交互来打开活动,对应的解决方法是开启一个全屏的通知.
这个一般针对电话,闹钟此类应用.
Android Q非SDK接口限制
与Android P 类似,具体的分析方法,可以参考官方的工具.
我们APP使用较少,主要是三方SDK的使用.
[参考文档]
https://juejin.im/post/5cad5b7ce51d456e5a0728b0#heading-10
https://developer.android.google.cn/preview/privacy/checklist
https://feng.moe/archives/47/?replyTo=23
网友评论