当应用的至少一个 intent 过滤器中存在 android:autoVerify="true"
时,在搭载 Android 6.0(API 级别 23)或更高版本的设备上安装应用会导致系统自动验证与应用 intent 过滤器中的网址相关联的主机。在 Android 12 及更高版本中,您还可以手动调用验证流程来测试验证逻辑。
自动验证
系统的自动验证涉及以下方面:
- 系统会检查所有包含以下任意项的 intent 过滤器:
- 操作:
android.intent.action.VIEW
- 类别:
android.intent.category.BROWSABLE
和android.intent.category.DEFAULT
- 数据架构:
http
或https
- 操作:
- 对于在上述 intent 过滤器中找到的每个唯一主机名,Android 会在
https:///.well-known/assetlinks.json
查询 Digital Asset Links 文件的相应网站。
确认要与您的应用关联的网站列表,并且确认托管的 JSON 文件有效后,请立即在您的设备上安装应用。等待至少 20 秒,让系统完成异步验证流程。使用以下命令检查系统是否验证了您的应用并设置了正确的链接处理政策:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d "http://domain.name:optional_port"
手动验证
从 Android 12 开始,您可以为安装在设备上的应用手动调用网域验证。无论您的应用是否以 Android 12 为目标平台,您都可以执行此流程。
建立互联网连接
如需执行网域验证,您的测试设备必须连接到互联网。
支持更新后的网域验证流程
如果您的应用以 Android 12 或更高版本为目标平台,则系统会自动使用更新后的网域验证流程。
否则,您可以手动启用更新后的验证流程。为此,请在终端窗口中运行以下命令:
adb shell am compat enable 175408749 PACKAGE_NAME
在设备上重置 Android App Links 的状态
在设备上手动调用网域验证之前,您必须在测试设备上重置 Android App Links 的状态。为此,请在终端窗口中运行以下命令:
adb shell pm set-app-links --package PACKAGE_NAME 0 all
此命令会将设备置于它在用户为任何网域选择默认应用之前所处的同一状态。
调用网域验证流程
在设备上重置 Android App Links 的状态之后,您可以执行验证本身。为此,请在终端窗口中运行以下命令:
adb shell pm verify-app-links --re-verify PACKAGE_NAME
查看验证结果
稍等片刻,在验证代理完成其请求之后,查看验证结果。为此,请运行以下命令:
adb shell pm get-app-links PACKAGE_NAME
此命令的输出类似于以下内容:
com.example.pkg: ID: 01234567-89ab-cdef-0123-456789abcdef Signatures: [***] Domain verification state: example.com: verified sub.example.com: legacy_failure example.net: verified example.org: 1026
成功通过验证的网域的网域验证状态为 verified
。其他任何状态都表示无法执行网域验证。特别是,状态为 none
表示验证代理可能尚未完成验证流程。
以下列表显示了网域验证可能会为给定的网域返回的值:
none
- 没有为此网域记录任何内容。再等待几分钟,以便验证代理完成与网域验证相关的请求,然后再次调用网域验证流程。
verified
- 为发出声明的应用成功验证了网域。
approved
- 强行批准了网域,通常是通过执行 shell 命令来实现的。
denied
- 强行拒绝了网域,通常是通过执行 shell 命令来实现的。
migrated
- 系统保留了使用旧版网域验证的某个先前流程的结果。
restored
- 在用户执行数据恢复之后批准了网域。系统假定网域之前已经过验证。
legacy_failure
- 旧版验证程序拒绝了网域。具体的失败原因未知。
system_configured
- 网域已通过设备配置自动批准。
- 错误代码为
1024
或更大 设备验证程序专用的自定义错误代码。
请求用户将您的应用与网域相关联
如需使您的应用获准处理某个网域,另一种方法是让用户将您的应用与该网域相关联。
检查您的应用是否已获准处理网域
在提示用户之前,请检查您的应用是否是您在 <intent-filter>
元素中定义的网域的默认处理程序。您可以使用以下某种方法来查询批准状态:
DomainVerificationManager
API(在运行时)。- 命令行程序(在测试过程中)。
DomainVerificationManager
以下代码段演示了如何使用 DomainVerificationManager
API:
Kotlin
val context: Context = TODO("Your activity or fragment's Context") val manager = context.getSystemService(DomainVerificationManager::class.java) val userState = manager.getDomainVerificationUserState(context.packageName) // Domains that have passed Android App Links verification. val verifiedDomains = userState?.hostToStateMap ?.filterValues { it == DomainVerificationUserState.DOMAIN_STATE_VERIFIED } // Domains that haven't passed Android App Links verification but that the user // has associated with an app. val selectedDomains = userState?.hostToStateMap ?.filterValues { it == DomainVerificationUserState.DOMAIN_STATE_SELECTED } // All other domains. val unapprovedDomains = userState?.hostToStateMap ?.filterValues { it == DomainVerificationUserState.DOMAIN_STATE_NONE }
Java
Context context = TODO("Your activity or fragment's Context"); DomainVerificationManager manager = context.getSystemService(DomainVerificationManager.class); DomainVerificationUserState userState = manager.getDomainVerificationUserState(context.getPackageName()); Map<String, Integer> hostToStateMap = userState.getHostToStateMap(); List<String> verifiedDomains = new ArrayList<>(); List<String> selectedDomains = new ArrayList<>(); List<String> unapprovedDomains = new ArrayList<>(); for (String key : hostToStateMap.keySet()) { Integer stateValue = hostToStateMap.get(key); if (stateValue == DomainVerificationUserState.DOMAIN_STATE_VERIFIED) { // Domain has passed Android App Links verification. verifiedDomains.add(key); } else if (stateValue == DomainVerificationUserState.DOMAIN_STATE_SELECTED) { // Domain hasn't passed Android App Links verification, but the user has // associated it with an app. selectedDomains.add(key); } else { // All other domains. unapprovedDomains.add(key); } }
命令行程序
在开发过程中测试您的应用时,您可以运行以下命令来查询贵单位拥有的网域的验证状态:
adb shell pm get-app-links --user cur PACKAGE_NAME
在以下示例输出中,虽然应用针对“example.org”网域的验证失败,但用户 0 已在系统设置中手动批准应用,并且没有其他软件包针对该网域进行验证。
com.example.pkg: ID: *** Signatures: [***] Domain verification state: example.com: verified example.net: verified example.org: 1026 User 0: Verification link handling allowed: true Selection state: Enabled: example.org Disabled: example.com example.net
您还可以使用 shell 命令来模拟用户选择与给定网域关联的应用的过程。adb shell pm
的输出提供了这些命令的完整说明。
提供请求的上下文
在您发出网域批准请求之前,请先为用户提供一些上下文。例如,您可以向用户显示启动画面、对话框或类似的界面元素,向用户说明为什么您的应用应该是某个特定网域的默认处理程序。
发出请求
在用户了解您的应用需要他们执行的操作之后,发出请求。为此,请调用一个 intent,其中包含 ACTION_APP_OPEN_BY_DEFAULT_SETTINGS
intent 操作,以及与目标应用的 package:com.example.pkg
匹配的数据字符串,如以下代码段所示:
Kotlin
val context: Context = TODO("Your activity or fragment's Context") val intent = Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, Uri.parse("package:${context.packageName}")) context.startActivity(intent)
Java
Context context = TODO("Your activity or fragment's Context"); Intent intent = new Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, Uri.parse("package:" + context.getPackageName())); context.startActivity(intent);
调用该 intent 时,用户会看到一个名为默认打开的设置屏幕。此界面包含一个名为打开支持的链接的单选按钮,如图 1 所示。
当用户开启打开支持的链接时,一个名为要在此应用中打开的链接的部分下会出现一组复选框。在此处,用户可以选择想要与您的应用关联的网域。他们还可以选择添加链接以添加网域,如图 2 所示。当用户稍后选择他们所添加网域中的任何链接时,该链接会自动在您的应用中打开。
在您的应用中打开您的应用无法验证的网域
您的应用的主要功能可能是用作第三方应用来打开链接,而无法验证其处理的网域。如果是这种情况,请向用户说明:当他们选择某个网页链接时,无法在第一方应用与您的(第三方)应用之间进行选择。用户需要手动将网域与您的第三方应用相关联。
此外,不妨考虑引入一个对话框或 trampoline activity 来充当代理,让用户能够在第一方应用中打开链接(如果用户愿意这样做的话)。在设置此类对话框或 trampoline activity 之前,请先设置您的应用,使其具有对满足以下条件的第一方应用的软件包可见性:与您的应用的网络 intent 过滤器匹配。