You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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的情况,跑通了再扩展到其他浏览器~

火山引擎 最新活动