Android启动器获取Chrome等浏览器“添加到主屏幕”创建的网页快捷方式问题
Android启动器获取Chrome等浏览器“添加到主屏幕”创建的网页快捷方式问题
我之前开发自定义启动器的时候,刚好碰到过一模一样的问题!那些通过Chrome这类浏览器「添加到主屏幕」生成的网页快捷方式,说穿了就是浏览器应用自带的特殊静态快捷方式,但之前你用LauncherApps.getShortcuts没捞到,大概率是过滤条件没卡对,也没把WebAPK和纯网页快捷方式区分开。下面给你捋捋具体的解决思路和代码实现:
一、先把权限配置到位
首先得确保你的启动器有能力获取其他应用的快捷方式:
- 如果你是针对Android 11+(API 30及以上),为了合规,建议在
AndroidManifest.xml里声明需要查询的浏览器包名,避免用QUERY_ALL_PACKAGES(这个权限过Play审核容易出警告):
<queries> <package android:name="com.android.chrome" /> <package android:name="org.mozilla.firefox" /> <!-- 加你需要支持的其他浏览器包名 --> </queries>
- 要是你需要兼容更低版本,或者必须覆盖所有应用,再添加这个权限(记得加tools忽略警告):
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
另外,你的启动器肯定已经声明了launcher的核心配置,这里再提个醒:
<activity ...> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
二、用LauncherApps精准筛选网页快捷方式
之前你只拿到WebAPK,是因为WebAPK是独立安装的小应用,它们的快捷方式属于自己的包;而我们要的网页快捷方式,是挂在浏览器包名下的ShortcutInfo。所以要针对每个浏览器包名单独查询,再过滤出网页类型的:
1. 核心查询代码(Kotlin)
val launcherApps = context.getSystemService(LauncherApps::class.java) // 以Chrome为例,你可以把常用浏览器包名存成列表遍历 val targetBrowserPackages = listOf("com.android.chrome", "org.mozilla.firefox") targetBrowserPackages.forEach { packageName -> if (launcherApps.isPackageEnabled(packageName)) { val shortcutQuery = LauncherApps.ShortcutQuery().apply { // 匹配静态+动态快捷方式,网页快捷方式属于静态范畴 setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_STATIC or LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC) setPackage(packageName) setUser(UserHandle.myUserHandle()) // 只处理当前用户 } try { val allBrowserShortcuts = launcherApps.getShortcuts(shortcutQuery, UserHandle.myUserHandle()) // 筛选出我们要的网页快捷方式 val webHomeShortcuts = allBrowserShortcuts.filter { shortcut -> when { // Android 11+ 可以直接用系统提供的类型判断,最准确 Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { shortcut.shortcutType == ShortcutInfo.SHORTCUT_TYPE_WEB } // 低版本只能通过Intent的特征来判断 else -> { val intent = shortcut.intent ?: return@filter false // 核心特征:ACTION_VIEW + http/https开头的URL val isWebIntent = intent.action == Intent.ACTION_VIEW && intent.data?.scheme?.startsWith("http") == true // 再加上浏览器的专属标识,避免误判 val isFromBrowser = when (packageName) { "com.android.chrome" -> intent.hasExtra("com.google.android.apps.chrome.SHORTCUT") "org.mozilla.firefox" -> intent.component?.className?.contains("FirefoxShortcutActivity") == true else -> true // 其他浏览器可以自己补充判断逻辑 } isWebIntent && isFromBrowser } } } // 到这里,webHomeShortcuts就是你要的那些主屏幕网页快捷方式了 webHomeShortcuts.forEach { shortcut -> Log.d("WebShortcut", "名称:${shortcut.shortLabel},链接:${shortcut.intent?.data}") // 可以把这些信息存到你的启动器数据模型里,用来展示 } } catch (e: SecurityException) { // 权限不足的情况,记得弹个提示或者引导用户授权 e.printStackTrace() } } }
2. 区分WebAPK和网页快捷方式的关键
WebAPK的包名格式一般是com.google.android.apps.chrome.webapk.xxx这类独立包名,而我们要的快捷方式包名是浏览器本身的(比如com.android.chrome),所以只要把查询范围限定在浏览器包名下,就能自动排除WebAPK的快捷方式。
三、实时监听快捷方式的新增/删除
如果你想让启动器实时同步用户新添加的网页快捷方式,可以注册LauncherApps.Callback来监听变化:
val shortcutCallback = object : LauncherApps.Callback() { override fun onShortcutsChanged(packageName: String, shortcutIds: MutableList<String>?, user: UserHandle?) { // 只有当变化的是我们关注的浏览器包名时,才重新查询 if (targetBrowserPackages.contains(packageName) && user == UserHandle.myUserHandle()) { // 调用上面写的查询方法,更新你的启动器界面 refreshWebHomeShortcuts() } } // 其他方法空实现就行 override fun onPackageRemoved(packageName: String, user: UserHandle?) {} override fun onPackageAdded(packageName: String, user: UserHandle?) {} override fun onPackageChanged(packageName: String, user: UserHandle?) {} override fun onPackagesAvailable(packageNames: MutableList<String>?, user: UserHandle?, replacing: Boolean) {} override fun onPackagesUnavailable(packageNames: MutableList<String>?, user: UserHandle?, replacing: Boolean) {} } // 在启动器的HomeActivity onCreate里注册 launcherApps.registerCallback(shortcutCallback) // 在onDestroy里记得注销,避免内存泄漏 override fun onDestroy() { super.onDestroy() launcherApps.unregisterCallback(shortcutCallback) }
最后踩坑提醒
- 不同浏览器的快捷方式Intent特征可能不一样,比如Firefox的网页快捷方式会用自己的专属Activity,你可以在调试的时候打印Intent的component信息,补充过滤条件。
- 有些用户可能禁用了浏览器的快捷方式权限?不过一般默认都是开着的,真碰到的话,引导用户去应用设置里开启“创建快捷方式”权限就行。
我当时就是这么调整了查询和过滤逻辑,一下子就拿到了那些之前没抓到的网页快捷方式,你可以先试试Chrome的情况,跑通了再扩展到其他浏览器~




