Android 11实现Chrome添加到桌面快捷方式功能布局显示异常问题
问题原因
- Android 11(API 30)对外部组件调用的权限校验更严格,你调整后的代码中
PinShortcutConfirm的android:exported属性设为false,首次触发时系统拦截了Chrome发起的外部Intent,仅创建了Activity实例但不给UI渲染权限,仅在Layout Inspector可见;第二次触发时应用进程已被唤起,系统临时放宽校验所以能正常显示。 - 弹窗Activity和主启动器Activity共用任务栈,主启动器的
launchMode设为singleTask且在后台运行时,系统会抑制该任务栈中新Activity的UI展示,避免打断前台应用(Chrome)的用户操作。 - 主题不兼容:Application使用AppCompat主题,弹窗Activity使用系统原生Material主题,首次Inflate布局时出现渲染异常,系统跳过UI绘制,第二次触发时布局已缓存所以正常显示。
ShortcutInfo强制解包可能导致空异常,首次触发时数据未完全加载就尝试渲染,触发异常后系统不展示界面。
修复方案
1. 修改AndroidManifest.xml配置
调整PinShortcutConfirm的属性如下:
<activity android:name="PinShortcutConfirm" android:theme="@style/Theme.AppCompat.Dialog" android:noHistory="true" android:excludeFromRecents="true" android:exported="true" android:launchMode="singleInstance" android:taskAffinity=""> <intent-filter> <action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
修改点说明:
exported改为true,允许接收外部应用发起的Intent- 增加
DEFAULT分类,匹配系统Intent的匹配规则 - 新增
launchMode="singleInstance"和空taskAffinity,让弹窗运行在独立任务栈,不受后台主启动器任务栈影响 - 主题改为AppCompat系列的Dialog主题,和Application主题兼容
2. 修改PinShortcutConfirm.kt代码
- 新增窗口标志,强制弹窗获得前台UI焦点
- 替换
ShortcutInfo的强制解包为安全调用,避免空异常
修改后的onCreate代码如下:
@SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 新增窗口标志,强制获得前台焦点 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { setShowWhenLocked(true) setTurnScreenOn(true) } else { window.addFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD ) } window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) setContentView(R.layout.pin_shortcut_confirm) mLauncherApps = getSystemService(LauncherApps::class.java) findViewById<View>(R.id.ok).setOnClickListener(this) findViewById<View>(R.id.cancel).setOnClickListener(this) mRequest = getSystemService(LauncherApps::class.java).getPinItemRequest(intent) mShortcutInfo = mRequest.shortcutInfo // 安全调用,避免空异常 mShortcutInfo?.let { info -> val description = findViewById<TextView>(R.id.shortcut_description) description.text = """ ID: ${info.id} Label: ${info.shortLabel} """.trimIndent() val icon = mLauncherApps.getShortcutIconDrawable(info, resources.displayMetrics.densityDpi) icon?.let { findViewById<ImageView>(R.id.image).setImageDrawable(it) } } ?: run { finish() return } }
3. 补充必要权限
在AndroidManifest.xml中添加启动器必要权限:
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" /> <uses-permission android:name="android.permission.CREATE_SHORTCUT" /> <!-- Android 11+包可见性权限,可正常获取Chrome发起的快捷方式信息 --> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" android:ignore="QueryAllPackagesPermission" />
内容的提问来源于stack exchange,提问作者El Nuru
相关产品推荐
相关产品推荐

