个推技术分享您有⼀份安卓12适配攻略,请注意查收!
10 ⽉ 4 ⽇,⾕歌将Android12源代码推送⾄ Android 开源项⽬ (AOSP)。⾃从2021年2⽉发布Android12第⼀个预览版以来,历经9个⽉时间测试和优化,正式版本的Android12终于来了!不仅在UI⽅⾯做了不少升级,Android12对个⼈隐私安全的保护也得到了进⼀步增强。整体来讲,Android12更加智能、⾼效和安全,感兴趣的开发者可以登录官⽹下载源码测试学习。
个推服务开发者多年,打磨SDK产品的同时,⼀直密切关注和跟进⾏业发展趋势。Android12稳定版发布后,我们使⽤模拟器进⾏了研究和适配测试。本⽂将从安全变更、权限变化、性能更新等⽅⾯来谈谈 Android12 新特性,以帮助开发者更快速、更便捷地上⼿适配Android新系统。
安全变更
01 更安全的组件导出
从事Android开发的同学都知道,Android有四⼤组件,分别是活动(Activity)、服务(Service)、⼴播接收器(Broadcast Receive)和内容提供器(Content Provider)。Activity组件为⽤户提供可视化操作界⾯;服务组件在后台运⾏,⽀撑各类功能的实现;⼴播接收器顾名思义主要⽤于接受各种⼴播;内容提供器主要⽀持多个应⽤中存储和读取数据,相当于⼀个数据库。
这四⼤组件赋予了App各种各样丰富的功能,因此⽆论是对App还是⽤户来讲,它们的安全性都⾄关重要。在App开发过程中,会有⼀些特定需求使⽤到第三⽅SDK,如⽀付、消息推送等,这些都会涉及到组件导出的问题。为保护隐私以及改善整体⽤户体验,Android12对组件的导出有了更严格的要求。
使⽤Android12的开发者需要关注,如果您对四个组件配置了intent 过滤器,则务必要在代码中显式声明android:exported 属性。如果未设置该属性,那应⽤将⽆法安装在 Android12 上。
android:exported 属性声明代码⽰例:
<service android:name="ample.app.backgroundService" android:exported="false"> <intent-filter> <action
android:name="ample.app.START_BACKGROUND" /> </intent-filter> </service>
02 PendingIntent
PendingIntent是⼀种特殊的Intent,和Intent的区别在于Intent是⽴刻执⾏的,⽽PendingIntent不是,可以被理解为⼀种异步处理机制。PendingIntent执⾏的操作实质上是参数传进来的Intent操作,像通知栏消息的发送就是使⽤PendingIntent实现。
为了提升应⽤的安全性,Android12新特性要求应⽤创建的每个PendingIntent对象都要指定可变性, 使⽤PendingIntent.FLAG_MUTABLE 或PendingIntent.FLAG_IMMUTABLE标志。
PendingIntent pendingIntent = Activity(getApplicationContext(), REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE);
如果不设置任⼀可变性标志, 系统将会抛出IllegalArgumentException异常,报错内容如下:
java.lang.IllegalArgumentException: XXX: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating
a PendingIntent.
03 不安全的intent启动
⽽对于⼀般的intent⽽⾔,开发者如何确保其安全性呢?Android12为开发者们提供了⼀种调试功能,如果应⽤以不安全的⽅式启动intent,此功能将会发出警告。具体实现也⽐较简单,开发者在application中添加以下代码即可:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { StrictMode.setVmPolicy(new StrictMode.
VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch().penaltyLog() // Consider also adding penaltyDeath() .build()); }
这⾥要⾮常注意嵌套intent。嵌套intent是在其他intent中作为extra传递的intent。如果有以下⾏为,系统将发⽣StrictMode违规警告:
①从intent的extra中解析提取嵌套intent。
②使⽤该嵌套intent启动应⽤组件,例如将intent传递给startActivity()。
隐私保护
为了更好地保障⽤户的个⼈信息,Android12引⼊了⼤致位置选项、应⽤休眠、ADB备份限制等新的隐私功能。
01 ⼤致位置选项
Android12之前,⽤户在授予位置信息访问权限时只能允许系统层⾯的设置,如果想要更改某⼀特定应⽤的位置权限,则需要到相应的设置界⾯进⾏⼿动处理。为了更好地保护⽤户隐私,Android12引⼊了“⼤致位置”选项。当应⽤需要访问位置权限时,弹窗将会出现“确切位置”和“⼤致位置”两个选项供⽤户进⾏授权:
确切位置,通常精确到⼏⽶之内。
⼤致(粗略)位置,⼀般为⼏百⽶。
位置信息⼀共有三种授权⽅式:仅在使⽤该应⽤时允许、仅限这⼀次和不允许。个推对这些授权⽅式进⾏了实测:
①如果Manifest 配置了且请求了Manifest.permission.ACCESS_COARSE_LOCATION位置弹框:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED { requestPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION }, 1); } }
在前端界⾯将会出现弹框如下:
②Android12要求,必须同时申请⼤致(粗略)位置和确切位置的权限,才能完成ACCESS_FINE_LOCATION 确切位置权限的授权。所以,如果Manifest没有配置<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION" />但是请求
Manifest.permission.ACCESS_FINE_LOCATION 弹框, 则前端界⾯会弹出和①情况⼀致的弹框,即“⼤致(粗略)位置弹框”。
③如果Manifest配置了和<uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION" /> ,且同时请求两个位置权限的弹框:自动弹窗代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); }} // 和以下代码调⽤ , 弹框⼀致requestPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }, 1); @Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) }}
在前端界⾯将会出现弹框如下:
④在第③种情况下,根据⽤户的选择,会出现以下⼏种情况:
如果⽤户选择了“确切位置”, 同时选择了“仅在使⽤该应⽤时允许”或者“仅限这⼀次”,onRequestPermissionsResult 参数int[] grantResults 两个返回值均为0,表⽰已授权,应⽤重启后权限将仍保持授权状态。
★也就是说,“仅限这⼀次”并⾮严格意义上的仅限这⼀次授权。对当前应⽤完成授权后,下次重启该应⽤将仍是已授权状态。
如果位置选择了“⼤致位置”, 同时选择了“仅限这⼀次”, onRequestPermissionsResult参数int[] grantResults返回值为0 和-1,意味着此次“⼤致位置”已经授权, 但“确切位置”仍未授权。下次启动再次调⽤requestPermissions(new String[]
{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 1), 则弹框如下: 从“⼤致位置”改为“确切位置”弹框询问,此时“⼤致位置”已默认授权。
如果⽤户选择 “继续使⽤⼤致位置”, 则int[] grantResults 返回值仍为0和-1 , 下次请求还会出现同样弹框内容。
如果选择“仅限这⼀次”, 则int[] grantResults返回值为0和0 ,下次启动应⽤时,两个位置权限将仍保持授权状态。
以上测试总结如下:
★ Android12的位置权限变更对旅游出⾏、地图导航、酒店预订等App影响较⼤。尤其是在“个保法”正式实施的背景下,App开发者更要关注系统和相关法律法规对位置信息授权⽅式的要求,做好个⼈信息安全的有效保护。⽐如,App需通过弹窗等显著的⽅式向⽤户申请个⼈信息的授权,在⽤户隐私条款中明确相关信息的⽤途、保存⽅式、处理⽅式等。
02 应⽤休眠
此外,Android12还对Android11 “⾃动撤销权限”功能进⾏了升级,引⼊了“应⽤休眠”功能。App⾃动休眠功能代码由⾕歌于今年⼀⽉份在AOSP系统项⽬中提交。这项功能可以让⽤户⾃⾏标记出⼀个应⽤列表,受标记的应⽤如果⼏个⽉未被使⽤,则系统会⾃动取消其权限、停⽌各种后台通知,将该应⽤置于休眠状态,以省电并移除其占有的应⽤空间。Android12的该功能不仅有助于释放⼿机存储空间,还将极⼤提升⽤户体验。
★对于⽤户交互频率较低的特定类型应⽤⽽⾔,开发者可以调⽤包含 Intent.ACTION_APPLICATION_DETAILS_SETTINGS intent 操作的intent,向⽤户发送请求,让其准许应⽤免于休眠和⾃动重置权限限制。
03 DB 备份限制
同时,为了帮助保护私有应⽤数据,Android12还更改了adb backup命令的默认⾏为。对于以Android12为⽬标平台的应⽤,当运⾏adb backup命令时,从设备导出的其他任何系统数据都不会包含应⽤的数据。
如果测试或开发⼯作流程依赖于使⽤adb backup的应⽤数据,则可以选择在AndroidManifest⽂件中将android:debuggable设置为true来导出应⽤数据。注意,release线上版本务必将android:debuggable设置为false。
性能更新
性能优化是Android系统每次版本更新的重点内容。Android12改进了应⽤程序启动时间并优化了I/O,以加快应⽤程序加载速度。同时,为改进⽤户体验,Android12对通知trampoline、前台服务启动以及闹钟权限等均进⾏了限制。
01 通知trampoline限制
当⽤户点击通知后,会启动⼀个组件来响应⽤户的点击操作, ⼀般最终会打开⼀个界⾯。这个界⾯组件就是通知trampoline。
考虑⼀种情形, 如果通知构建的PendingIntent使⽤了Service或者 Br
oadcast, 那么,当打开通知时后台可能需要做⼀些耗时操作或者请求⽹络等, 等处理完成之后再跳转到⽬标页⾯。但有时候⽹络、耗时操作等各种原因会造成等候时间较长, 进⽽导致界⾯弹出较晚, 以致⼏秒后才跳转出⼀个页⾯, 这种体验相对⽽⾔⽐较差。
为了改进⽤户体验,以Android12为⽬标平台的应⽤⽆法从⽤作通知 trampoline的服务或者⼴播中启动activity,也就是说应⽤构建的通知setContentIntent()参数必须是 Activity。
个推对该功能进⾏了测试:
创建通知, setContentIntent() PendingIntent参数使⽤getService或者Broadcast构建 PendingIntent;
通知触发的⽬标组件, 也就是点击通知后启动的Service或者Broadcast, 启动某个Activity;
弹出通知后, 应⽤切换到后台, 此时再点击通知, 会报以下错误, 且最终页⾯⽆法被启动。
system_process E/NotificationService: Indirect notification activity start (trampoline) brand.push.system_process E/ActivityTaskManager: Abort background activity starts from 10146
对于⼤部分App开发者来讲,实现通知trampoline的兼容,只需要将应⽤构建的通知 setContentIntent()参数修改为 Activity 即可。
但是对于有特殊功能需求的开发者来讲,如果之前的业务逻辑是点击通知以后需启动服务/⼴播,并在服务/⼴播中完成⼀些动作(⽐如打点或者发送回执)后才启动⽬标 Activity,那么直接将setContentIntent()参数改为 Activity,同时这个⽬标Activity正好是第三⽅页⾯的话,点击通知后,直接启动的就是第三⽅页⾯,⽽开发者⾃⾝的业务需求则将⽆法得到处理。
针对此情况,个推提出了两个可参考的⽅案:
①在SDK中新增⼀个透明中转 Activity, 通知点击启动这个透明Activity 之后, 在透明Activity onCreate ⽅法中再启动⽬标服务或者⼴播, 后续逻辑保持⼀致。theme务必配置成android:style/Theme.Translucent.NoTitleBar, 透明activity务必记得要在onCreate最后调⽤finish⽅法销毁这个页⾯。
<activity android:name="透明中转 activity" android:excludeFromRecents="true" android:exported="false" android:taskAffinity="xxx"
android:theme="@android:style/Theme.Translucent.NoTitleBar" > </activity>
②新增⼀个BaseActivity, 在BaseActivity完成业务逻辑,⽬标Activity继承这个BaseActivity, 并让⽬标Activity调⽤super⽅法。
相⽐第⼆种⽅案,第⼀种⽅案对客户来讲⽆需做额外处理,集成起来更加⽅便。因此,个推SDK产品使⽤的就是第⼀种⽅案进⾏Android12
适配。
02 前台服务启动限制
03 精确的闹钟权限
闹钟是应⽤安排定时⼯作的重要⽅式。在⼤多数情况下,应⽤应该使⽤⾮精确闹钟(inexact alarms),这样可以减少电池消耗。然⽽对于提供时间管理、⽇程安排等服务的App⽽⾔,必须使⽤精确的闹钟权限才能实现相关功能。精确闹钟功能⾮常⽅便可靠,但也会加⼤电量消耗。为增加⽤户的⾃主权,提升⽤户体验,Android12 对精确的闹钟权限进⾏了限制。
在Android12系统下,开发者如果想要使⽤精确闹钟,则需要在 l ⽂件中添加该权限的申请:
setAlarmClock()
setExact()
setExactAndAllowWhileIdle()
如下图,⽤户在设置>应⽤>特殊应⽤权限>闹铃和提醒可以看到需要精确闹钟权限的应⽤列表:
并且,⽤户可以为某⼀特定应⽤⼿动关闭或打开该权限:
总结
针对Android12的新特性,个推消息推送SDK进⾏了适配测试。开发者⽤户可联系@个推技术⽀持了解个推消息推送SDK最新版本,完成对Android12的兼容。
扫码添加@个推技术⽀持
后续,个推还将持续关注安卓系统和⾏业发展动态,与开发者们交流相关开发知识和技术原理,共同推进移动互联⽹的快速发展。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论