软件包可见性
软件包可见性是Android
11上提升系统隐私安全性的一个新特性。它的作用是限制app随意获取其他app的信息和安装状态。避免病毒软件、间谍软件利用,引发网络钓鱼、用户安装信息泄露等安全事件。
获取自动可见应用的列表,可以执行命令adb shell dumpsys package queries,找到 forceQueryable
部分。下面是在vivo iqoo手机的执行结果。
Queries: system apps queryable: false forceQueryable: [com.android.BBKCrontab,com.vivo.fingerprint,com.vivo.epm,com.vivo.abe,com.vivo.fingerprintengineer,com.vivo.contentcatcher,com.vivo.floatingball,com.vivo.agent,com.vivo.nightpearl,android,com.wapi.wapicertmanage,com.vivo.vms,co m.android.providers.settings,com.vivo.upslide,com.vivo.assistant,com.vivo.vivokaraoke,com.vivo.fingerprintui,com.android.wallpaperbackup,com.bbk.facewake,com.vivo.faceunlock,com.vivo.doubleinstance,com.vivo.audiofx,com.iqoo.powersav ing,com.bbk.SuperPowerSave,com.vivo.vibrator4d,com.vivo.smartunlock,com.vivo.globalanimation,com.vivo.appfilter,com.vivo.voicewakeup,com.vivo.minscreen,com.android.bbklog,com.mobile.cos.iroaming,com.vivo.networkstate,com.vivo.daemon Service,com.vivo.smartshot,com.vivo.vtouch,com.android.networkstack.tethering.inprocess,com.android.localtransport,com.vivo.pem,com.vivo.wifiengineermode,com.android.server.telecom,com.vivo.gamecube,com.vivo.aiengine,com.vivo.multin lp,com.vivo.smartmultiwindow,com.vivo.permissionmanager,com.qti.diagservices,com.vivo.bsptest,com.qti.snapdragon.qdcm_ff,com.vivo.dr,com.vivo.sps,com.android.dynsystem,com.vivo.setupwizard,com.vivo.gamewatch,com.android.keychain,com .vivo.faceui,com.android.networkstack.inprocess,com.android.location.fused,com.android.inputdevices,com.android.settings,com.iqoo.engineermode,com.vivo.fuelsummary] [com.qualcomm.uimremoteserver,com.vivo.devicereg,com.qti.qualcomm.deviceinfo,com.volte.config,com.android.mms.service,com.android.ons,com.qualcomm.qcrilmsgtunnel,com.vivo.sim.contacts,com.qualcomm.qti.uimGbaApp,com.qualcomm.qti. modemtestmode,com.android.stk,com.android.vendors.bridge.softsim,com.qualcomm.uimremoteclient,com.qti.qualcomm.datastatusnotification,com.qualcomm.qti.uim,com.android.phone,com.qualcomm.qti.dynamicddsservice,com.qualcomm.qti.telepho nyservice,com.android.cellbroadcastservice,com.android.providers.telephony,com.qti.dpmserviceapp,com.android.incallui] [com.android.vivo.tws.vivotws,com.android.bluetooth] com.android.nfc com.android.se com.android.networkstack.permissionconfig com.android.shell com.android.providers.media.module com.android.wifi.resources.overlay.common com.android.theme.icon_pack.filled.themepicker com.android.theme.icon_pack.circular.themepicker com.android.server.telecom.overlay.common ......
可以看到都是系统应用包名,所以我们的三方应用默认是不可见的。此项变更影响比较多的是分享支付一类需要与其他应用交互的功能。下面举一个简单的例子:
private static boolean hasActivity(Context context, Intent intent) { PackageManager packageManager = context.getPackageManager(); return packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0; } public void test() { Intent intent = new Intent(); intent.setClassName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareImgUI"); Log.d("hasActivity:", hasActivity(this, intent) + ""); }
hasActivity方法中通过queryIntentActivities来判断此页面是否存在。但是在targetSdkVersion >= 30中,这些三方默认都是不可见的。所以都会返回false。类似方法getInstalledPackages、getPackageInfo也受到相应的限制。
解决方法很简单,在AndroidManifest.xml 中添加queries元素,里面添加需要可见的应用包名。
<manifest package="com.example.app"> <queries> <package android:name="com.tencent.mm" /> <- 指定微信包名 </queries> ... </manifest>
我在适配中用到的还有下面的包名,我们可以按需添加:
<queries> <!-- 微博 --> <package android:name="com.sina.weibo" /> <!-- QQ --> <package android:name="com.tencent.mobileqq" /> <!-- 支付宝 --> <package android:name="com.eg.android.AlipayGphone" /> <!-- AlipayHK --> <package android:name="hk.alipay.wallet" /> </queries>
除了直接添加包名的方式外,我们可以按intent和provider来添加:
<manifest package="com.example.app"> <queries> <intent> <action android:name="android.intent.action.SEND" /> <data android:mimeType="image/jpeg" /> </intent> <provider android:authorities="com.example.settings.files" /> </queries> ... </manifest>
具体的规则参见:管理软件包可见性
当然,还有一种简单粗暴的方式,可以直接申请权限QUERY_ALL_PACKAGES。如果你的应用需要上架Google Play,那么可能要注意相关政策。为了尊重用户隐私,建议我们的应用按正常工作所需的最小软件包可见性来适配。
有一点需要说明一下,我们日常使用的startActivity
方法不受系统软件包可见性行为的影响,即使hasActivity为false,一样可以跳转。如果我们在做跳转前,进行类似hasActivity的判断,那么会受影响。
最后需要注意的是 ,使用queries元素需要Android Gradle 插件版本是 4.1及以上
,因为旧版本的插件并不兼容此元素,出现合并 manifest 的错误。
前台服务类型
Android 10中,在前台服务访问位置信息,需要在对应的service中添加 location 服务类型。
同样的,Android 11中,在前台服务访问摄像头或麦克风,需要在对应的service中添加camera或microphone 服务类型。
<manifest> ... <service android:name="MyService" android:foregroundServiceType="microphone|camera" /> </manifest>
这一限制的变更,使得程序无法在后台启动服务访问摄像头和麦克风。如需使用,只能是前台开启前台服务。除非有如下情况:
- 服务由系统组件启动。
- 服务是通过应用小部件启动。
- 服务是通过与通知交互启动的。
- 服务是PendingIntent启动的,它是从另一个可见的应用程序发送过来的。
- 服务由一个应用程序启动,该应用是一个DPC,且在设备所有者模式下运行。
- 服务由一个提供VoiceInteractionService的应用启动。
- 服务由一个具有START_ACTIVITIES_FROM_BACKGROUND权限的应用启动。
权限自动重置
如果应用以 Android 11 或更高版本为目标平台并且数月未使用,系统会通过自动重置用户已授予应用的运行时敏感权限来保护用户数据。如下图所示:
注意上图中有一个启动自动重置的开关。如果我们的应用有特殊需要,可以引导用户关闭它。示例代码如下:
public void checkAutoRevokePermission(Context context) { // 判断是否开启 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !context.getPackageManager().isAutoRevokeWhitelisted()) { // 跳转设置页 Intent intent = new Intent(Intent.ACTION_AUTO_REVOKE_PERMISSIONS); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setData(Uri.fromParts("package", context.getPackageName(), null)); context.startActivity(intent); } }
SYSTEM_ALERT_WINDOW权限
这部分我在适配中没有用到,直接照搬文档:
在 Android 11 中,系统会根据请求自动向某些类型的应用授予 SYSTEM_ALERT_WINDOW 权限:
- 系统会自动向具有 ROLE_CALL_SCREENING 且请求 SYSTEM_ALERT_WINDOW 的所有应用授予该权限。如果应用失去 ROLE_CALL_SCREENING,就会失去该权限。
- 系统会自动向通过 MediaProjection 截取屏幕且请求 SYSTEM_ALERT_WINDOW 的所有应用授予该权限,除非用户已明确拒绝向应用授予该权限。当应用停止截取屏幕时,就会失去该权限。此用例主要用于游戏直播应用。
这些应用无需发送 ACTION_MANAGE_OVERLAY_PERMISSION 以获取 SYSTEM_ALERT_WINDOW
权限,它们只需直接请求 SYSTEM_ALERT_WINDOW 即可。
MANAGE_OVERLAY_PERMISSION intent 始终会将用户转至系统权限屏幕
从 Android 11 开始,ACTION_MANAGE_OVERLAY_PERMISSION intent
始终会将用户转至顶级设置屏幕,用户可在其中授予或撤消应用的 SYSTEM_ALERT_WINDOW 权限。intent 中的任何 package:
数据都会被忽略。
在更低版本的 Android 中,ACTION_MANAGE_OVERLAY_PERMISSION intent
可以指定一个软件包,它会将用户转至应用专用屏幕以管理权限。从 Android 11
开始将不再支持此功能,而是必须由用户先选择要授予或撤消哪些应用的权限。此变更可以让权限的授予更有目的性,从而达到保护用户的目的。
读取手机号
如果你是通过TelecomManager的getLine1Number方法,或TelephonyManager的getMsisdn方法获取电话号码。那么在Android
11中需要增加READ_PHONE_NUMBERS权限。使用其他方法不受限。
<manifest> <!-- 如果应用仅在 Android 10及更低版本中使用该权限,可以添加 maxSdkVersion="29" --> <uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="29" /> <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" /> </manifest>
4.其他行为变更
自定义view的Toast
Android 11 为目标平台的应用,从后台发送自定义view的Toast消息系统会进行屏蔽。 前台使用不受影响
。Toast相应的setView 和 getView也已经废弃不建议使用。
如果要在后台使用,推荐使用默认的toast或Snackbar替代。
APK签名
Android 11 为目标平台的应用,仅通过v1 签名的应用无法在Android 11的设备上安装或更新。必须使用v2或更高版本进行签名。
同时Android 11 添加了对 APK 签名方案
v4 的支持。