具有动态功能的即时应用程序始终显示带有 1 个选项的消歧对话框

Instant app with Dynamic Features always show Disambiguation dialog with 1 option

我正在试验动态功能和免安装应用程序。 为了在各种功能之间导航,我使用深层链接。

每次我导航到另一个 Activity,我都会看到不到 1 秒的消歧对话框,其中列出了 1 个应用程序。请注意 "Once" 和 "Always"(荷兰语)的选项是如何变灰的。

样本Github项目

我创建了一个 minimalistic sample,与我在 Github 上的当前结构相匹配。需要 Android Studio 3.5 - RC2

一些上下文:

我很有信心,深度link配置正确。但是既然你们想检查一下,这里是配置:

1 - 清单:

<activity
            android:name=".ProfileActivity">

        <intent-filter
                android:autoVerify="true"
                android:priority="100">

            <action android:name="android.intent.action.VIEW" />

            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />

            <data
                    android:host="giddy.entreco.nl"
                    android:pathPrefix="/profile"
                    android:scheme="http" />
            <data android:scheme="https" />

        </intent-filter>

    </activity>

2 - 资产links 我的域包含可公开访问的 assetlinks.json

3 - Sha 是正确的 我使用的 sha 是正确的

Executing tasks: [signingReport] in project

SHA1: 3A:52:19:77:C1:AD:18:F4:98:21:77:74:37:DC:9B:89:02:64:6E:C6
SHA-256: 25:DD:C3:7B:8E:35:D3:39:D5:D4:6C:B5:EA:7D:14:AF:82:EC:9C:56:A6:F5:76:A3:E1:D7:69:B3:EC:58:72:E8
Valid until: Saturday, March 21, 2048

4 - 确认数字资产link文件 所有检查通过 https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://giddy.entreco.nl&relation=delegate_permission/common.handle_all_urls

5 - 测试 URL 意图 也有效!唯一的问题是我在短时间内看到了消歧对话框。

附加信息

有什么建议可以消除烦人的对话吗? 当我分析 apk/bundle 时,我 确实看到 两个特定 Activity 的条目。曾经在base module's manifest,又在profile module's manifest。我对 Android/PlayStore 如何在安装模块时合并这些清单知之甚少,但我想在这种情况下看到对话框可能有意义。

所以是的......我相信我以前见过这个,当通过 URL 意图从一个动态特征(即时)导航到另一个(非即时)时,这是一些奇怪的行为。

在这个问题得到解决之前,我不建议使用 URL 意图在模块之​​间导航,而是使用反射直接到达另一个模块的 activity,示例:

if (doesModuleExist()) {
    val intent = Intent()
        .setClassName(getPackageName(), "com.sample.ProfileActivity")
        .addCategory(Intent.CATEGORY_DEFAULT)
        .addCategory(Intent.CATEGORY_BROWSABLE)
    startActivity(intent)
}

其中 doesModuleExist() 检查是否:

  1. 检查您的示例清单,您的配置文件模块似乎不是您的免安装应用程序的一部分 dist:instant="false",因此您永远无法访问它,因此您可以简单地执行 isNotInstantApp() 改为检查并且从不尝试在作为即时应用程序时启动。

  2. 在您安装的应用程序中,从技术上讲您不需要检查,因为它总是 include="true"

  3. 但是如果你的配置文件模块是一个 onDemand 模块,或者只是为了安全预防措施,你应该使用 splitInstallManager.getInstalledModules(),参见 /app-bundle/playcore#manage_installed_modules (注意,你也可以在您的免安装应用中使用此 API)

而且由于看起来这种奇怪的行为在不同设备之间有所不同,这可能意味着它们在拦截和处理 URL 意图方面存在细微差别,and/or 这只是一个不同的 Android 版本(pre-O vs O+)。

同样,将多个包名称与 common.handle_all_urls 的单个网站域相关联可能会在您的应用上线时系统尝试验证关联时导致一些额外的错误行为。

有一种可能的解决方案,可以使用具有动态功能的 URI 意图而不是切换到反射。您可以使用一个技巧,您可以在 运行 时间内使用 packageManager.queryIntentActivities() 获得所需的 class 名称,这样您就不必使用硬编码的 Activity 名称。

以下扩展函数是一个示例,说明如何使用 URI 或深度 link 将 Intent 转换为不显示选择器对话框的 Intent:

fun Intent.convertToSafeDynamicFeatureModuleIntent(context: Context) {
    //Get list of all intent handlers for this Intent. This should only be the actual activity we are looking for
    val options = context.packageManager.queryIntentActivities(this, PackageManager.MATCH_DEFAULT_ONLY)
    //Set the activity that supported the given intent
    setClassName(packageName, options[0].activityInfo.name)
}

那么你可以简单地做:

intent.convertToSafeDynamicFeatureModuleIntent(context)
startActivity(intent)

可以找到更长的解释here