Assetlinks.json 中的应用链接意图过滤器在 Android 上不起作用

Posted

技术标签:

【中文标题】Assetlinks.json 中的应用链接意图过滤器在 Android 上不起作用【英文标题】:App links intent filters in assetlinks.json not working on Android 【发布时间】:2016-06-01 19:13:16 【问题描述】:

我的应用定义了意图过滤器来处理来自我的站点的 URL,由

<intent-filter android:autoVerify="true">
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <data android:host="www.host.com" android:scheme="http"/>
</intent-filter>
<intent-filter android:autoVerify="true">
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <data android:host="www.host.com" android:scheme="https"/>
</intent-filter>

应用程序正确检测到正确主机的 URL,但询问用户是在应用程序还是浏览器中打开它们。我尝试使用此处指定的应用链接验证:https://developer.android.com/training/app-links/index.html

从我的服务器日志中可以看出,在安装应用程序时,设备会查询 /well-known/assetlinks.json 并以 200 状态响应。使用

测试数字资产文件

https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://&lt;domain1&gt;:&lt;port&gt;&amp;relation=delegate_permission/common.handle_all_urls

API 并没有发现错误。

assetlinks.json 文件中的 SHA256 是使用

获取的
keytool -list -v -keystore my-release-key.keystore 

与应用签名相同的 .keystore。

运行adb shell dumpsys package d 返回链接验证状态为“询问”,表示验证失败。为什么验证会失败?

【问题讨论】:

嗨@mohamed.ahmed 你能解决这个问题吗?我有类似的问题。在上传到 Play 商店之前,我的 android 应用程序链接适用于已签名的 apk。将其带到游戏商店后停止工作。请参阅链接以获取更多信息***.com/questions/57959217/… 也许您已将本地证书中的 SHA256 放入您的资产文件(在服务器中)。您需要将 SHA256 从 playGoogle 放入。 ***.com/a/61204765/496637 【参考方案1】:

对我们来说,这是 Windows 行尾!

使用“https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://domain1:port&relation=delegate_permission/common.handle_all_urls”进行测试证明是无价的,因为它给了我们“无法解析语句列表(无效 JSON)”错误,导致我们遇到了问题。

提示:最好使用 Android Studio App Links Assistant 中的“保存文件”按钮,而不是像我们所做的那样复制和粘贴 - 这样它会自行生成文件并保证不会出现此问题。

【讨论】:

这个答案让我走上了正确的道路,但对我来说,它实际上是字节顺序标记 (BOM),而不是行尾。我删除了 BOM,文件在 Windows 行结尾处工作得很好。有关如何删除 BOM 的详细信息,请参阅我的回答。 我先将它剪切并粘贴到记事本中,它为我解决了这个问题。找不到保存文件按钮。【参考方案2】:

有一些常见的陷阱你应该检查两次(我不是说你做错了。这只是一个检查清单):

    验证assetlinks.json 是否有效并存储可从https://example.com/.well-known/assetlinks.json 访问,您需要访问https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site= https://example.com&amp;relation=delegate_permission/common.handle_all_urls,必须没有错误。 如果您一次链接多个域,请检查所有域是否都按照步骤 1 正确设置。 确保那些包含&lt;data&gt; 标签的&lt;intent-filters&gt; 具有android:autoVerify="true" 属性。

    验证您的&lt;application&gt; 标记中是否包含所需的&lt;meta-data&gt; 标记:

    <meta-data
        android:name="asset_statements"
        android:resource="@string/asset_statements"/>
    

    asset_statements 字符串的内容必须是:

    <string name="asset_statements" translatable="false">[\"include\": \"https://example.com/.well-known/assetlinks.json\"]
    

    还用于调试发布签名证书(不要害怕您不能意外上传)在您的build.gradle 中使用它:

    buildTypes 
        release 
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        
        debug 
            debuggable true
            signingConfig signingConfigs.release
        
    
    

【讨论】:

另外,我还要补充一点,如果您有相同的根主机,但具有指向同一活动的不同路径值(如果您使用 .well-known 流程实现它),则应用程序链接将不起作用。我需要这个来同时在我的测试服务器和生产环境中测试我的功能。 @string/asset_statements 将如何提供帮助?特别是如果它只有一个 URL,而在 AndroidManifest 我们有多个。 奇怪,但是当我将两个域(从 AndroidManifest)添加到 asset_statements 时它有所帮助。但是后来又不行了,所以我删除了&lt;meta-data&gt;【参考方案3】:

对我来说,它归结为检查所有基础知识:

    使用此工具验证我的assetLinks 文件是否良好:(将 domain1:port 替换为您的域) https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://domain1:port&relation=delegate_permission/common.handle_all_urls 始终使用签名的 APK 进行测试 确保测试设备运行的是 Android 6.0 或更高版本(这是因为我忘记了它而让我苦恼的设备 - 在旧版本的 android 上,您总是会收到用户提示)

【讨论】:

非常感谢,这指出了问题所在。【参考方案4】:

查看j__m的评论,我发现了这个。

    AndroidManifest这样写:

     <intent-filter android:autoVerify="true">
         <action android:name="android.intent.action.VIEW" />
    
         <category android:name="android.intent.category.DEFAULT" />
         <category android:name="android.intent.category.BROWSABLE" />
    
         <!-- Write <data> tags with one attribute, if you use several domains. -->
         <data android:scheme="https" />
         <data android:host="example.com" />
     </intent-filter>
     <!-- Other domains-->
     <intent-filter android:autoVerify="true">
         <action android:name="android.intent.action.VIEW" />
    
         <category android:name="android.intent.category.DEFAULT" />
         <category android:name="android.intent.category.BROWSABLE" />
    
         <data android:scheme="https" />
         <data android:host="server.com" />
     </intent-filter>
    

应用链接需要android:autoVerify="true"

    使用Tools &gt; App Links Assistant 创建assetlinks.json。然后按Open Digital Asset Links File Generator,输入域,应用程序ID,选择release签名配置并按Generate Digital Asset Links File。然后您可以保存文件或复制到剪贴板。

    您可以创建多个 assetlinks.json 文件(用于多个应用程序)并将它们连接到一个 JSON 中。在我看来,它不依赖于 Windows 行尾(我使用记事本连接 JSON)。第一次我用 Ctrl + Alt + L 自动格式化它,上传到域后,App Link 不起作用(可能是因为AndroidManifest 中的后来错误),所以第二次尝试我没有格式化 JSON。我为应用程序的releasedebug 构建创建了assetlinks.json

    assetlinks.json 上传到https://example.com/.well-known/assetlinks.json(在此答案中,我写的是:example.com,表示您的域,如company.name)。使用https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&amp;relation=delegate_permission/common.handle_all_urls 进行检查。该文件和域有一些restrictions。就我而言,一切都很简单,我们没有更改设置。

    在您的DeepLinkActivity 中,您可以使用正则表达式解析 URL。使用JUnit 创建测试。从onCreate()调用这个方法:

     private fun processDeepLink() 
         if (intent?.data?.isHierarchical == true) 
             val data = intent?.dataString
             if (intent?.action == Intent.ACTION_VIEW && data != null) 
                 when 
                     REGEX.matches(data) -> // Get id and open some screen.
                     else -> // Either open MainActivity or skip this URL (open web browser instead).
                 
                 finish()
             
         
     
    
     companion object 
         val REGEX = "^https://example.com/some_request/(\\d+).*".toRegex()
     
    

警告!如果您从应用程序打开网络浏览器,您将陷入循环。在应用程序中单击指向您的域的链接时,不会出现浏览器,但您的应用程序会自动打开!多么惊喜!因此,在processDeepLink 中,您应该检查 URL 并在 URL 与您的掩码之一匹配时打开 MainActivity。跳过其他人。现在用户将看到一个包含浏览器列表和您的应用程序的对话框(就像在 Deep Link 中一样)。发生这种情况是因为您的应用程序还处理指向您的域的链接,例如浏览器。

您也可以使用WebView 代替浏览器(不是一个好的解决方案),打开Chrome Custom TabsChrome

    使用搭载 Android 6 或更高版本的设备。

    如果https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&amp;relation=delegate_permission/common.handle_all_urls 没有返回错误,则构建应用程序。创建包含指向您的域的链接的电子邮件、短信、二维码或其他应用程序。单击它,App Link 将打开您的应用程序,或者 Deep Link 将显示一个对话框以选择应用程序。 如果 App Link 不起作用,请稍后阅读。

    LogCat 中选择No Filters 并在搜索框中输入IntentFilter。应该有:

     I/IntentFilterIntentOp: Verifying IntentFilter. verificationId:2 scheme:"https" hosts:"example.com" package:"com.my_package".
     I/IntentFilterIntentOp: Verification 0 complete. Success:true. Failed hosts:.
    

你可能会得到:

I/IntentFilterIntentOp: Verifying IntentFilter. verificationId:0 scheme:"https" hosts:"example.com server.com" package:"com.my_package".
I/IntentFilterIntentOp: Verification 0 complete. Success:false. Failed hosts:server.com.

    稍后您将尝试修复应用程序中的域,因此有时您可以启动以进行全新安装:

     adb shell pm clear com.android.statementservice
    

    启动 adb shell dumpsys package d 并找到您的域。应该有:

    Package Name: com.my_package
    Domains: example.com server.com
    Status:  always : 200000000
    

但可能会是:

Package Name: com.my_package
Domains: example.com server.com
Status: ask

另见https://chris.orr.me.uk/android-app-linking-how-it-works/。奇怪,但在模拟器中它写道:always,而 App Link 不起作用。

我也试过adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://example.com"在没有浏览器的情况下测试App Link,但后来还是不行。

    如果您有多个域,请评论(或删除)AndroidManifest 中的其他域(仅保留一个域,例如“example.com”)。然后单击 URL https://example.com/something 并检查它是否使用 App Link。 就我而言,我检查了应用程序的 releasedebug 构建。 debug 构建与 App Link 一起使用,release 没有(有时反之亦然)。我用rekire的解决方案:

    <meta-data
        android:name="asset_statements"
        android:resource="@string/asset_statements"/>
    

它帮助了 2 个域,但后来停止了,所以我删除了它。最后我在AndroidManifest&lt;data&gt;标签中写了一个属性为j__m说的。

即使只有一个域出现故障,App Link 也不适用于其他域。您可以在AndroidManifest中逐个检查域,每次只保留一个域。

另见http://androidideas.com/handling-app-links-in-android/、https://willowtreeapps.com/ideas/a-better-user-experience-for-deep-linking-on-android、https://developer.android.com/training/app-links/verify-site-associations、

【讨论】:

【参考方案5】:

对我来说,我的 assetlinks.json 文件是 UTF-8 并且包含 字节顺序标记 (BOM),这是一个位于向消费程序发送编码信号的文件。 BOM 是可选的,显然 Google/Android 工具不喜欢看到它。当它出现时,Google 的数字资产链接验证器(下面的 URL)给了我一个“格式错误的 JSON”错误。

如果您使用的是 Visual Studio,以下是如何确定您的文件中是否有 BOM,并在必要时将其删除:

    右键单击您的assetlinks.json 文件。 从上下文菜单中选择“打开方式...”。 在“打开方式”对话框中选择“二进制编辑器”。 检查文件字节。如果文件以EF BB BF 开头,那就是问题所在。 删除这些字符(您可以通过任一列执行此操作)并保存文件。 重新上传文件并使用 Google 工具(以下网址)对其进行测试,它应该可以正常工作。

这是您可以用来检查文件的 URL(将 example.com 替换为您的实际 URL):

https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls

【讨论】:

【参考方案6】:

更新

所以我解决了我的问题。不确定是哪一个(可能是组合),但这就是我所做的:

已卸载“即时应用程序的 Google Play 服务”:我之前曾修改过即时应用程序,所以我认为可能一些旧配置可能会像调试包名称一样保留,但这不太可能。 已停止使用代理:代理有助于调试网络调用,但我使用的工具可能不完全支持 HTTP/2。 删除旧子域的意图过滤器:这是一个重要的。我的一个子域已被弃用,不再可用。在 AndroidManifest 中,如果您为包含至少一个 autoVerify 意图过滤器的活动声明了多个主机名,则会检查每个主机的数字资产链接 JSON 文件。 如果自动验证对于一个主机都失败了,那么所有主机都不会被自动验证。

原创

当我第一次遇到这个问题时,是因为我的网络阻止了对 Google 服务器的调用以验证应用链接。

正如 OP 和其他答案所涉及的那样,通常 API 调用端点:

digitalassetlinks.googleapis.com

必须成功绕过选择器对话框。 这是 Android 系统为验证数字资产链接 JSON 文件而进行的网络调用,似乎是在应用安装/更新时进行的。一个有用的地方是 Logcat,它搜索带有文本“I/SingleHostAsyncVerifier:”的项目。如果您在日志末尾看到“--> true”,则表明您的应用

但最近,由于最近可能引入了一些错误,这些调用对我来说一直失败。设备正在接收来自上述 API 调用的响应:

错误:不可用:从 host/.well-known/assetlinks.json 获取语句时 HTTP 响应标头中的内容类型错误(相当于“host/.well-known/assetlinks.json”) :预期“内容类型:应用程序/json”,但在从 host./.well-known/assetlinks.json 获取 Web 语句时找到了 text/html [11]

自从我上次查看这些请求以来已经有一段时间了,所以我不记得它们之前的样子了。但似乎最近可能有一些涉及 App Links 或 Android 网络框架的更新,他们切换到此功能的协议缓冲区(并忘记在另一个中支持它)。

另一个表明事情可能已经改变的迹象是,今天的请求路径与之前的答案中提到的不同:

https://digitalassetlinks.googleapis.com/google.digitalassetlinks.v1.AssetLinks/Check

【讨论】:

【参考方案7】:

对我来说,不要更改 assetlinks.json 的任何内容,包括修剪 blanksline-breaks

【讨论】:

【参考方案8】:

在我们的例子中,我们的清单中有 2 个带有应用链接的意图过滤器:一个带有 autoVerify="true",一个没有。

因此验证程序尝试验证第二个意图过滤器的域并失败,并将我们所有的应用链接视为“未验证”。您可以在this question找到更多详细信息。

您必须确保可以验证每个应用链接(这意味着为每个要验证的域添加 assetlinks.json)。

【讨论】:

【参考方案9】:

我确定这不能回答最初的问题,因为我认为它早于 Android App Bundles,但最终导致我失败的是我启用了 Google Play Console 重新签名的应用程序(AAB 需要),因此我从 keytool 获得的 SHA-256 指纹与下载的应用程序的数字签名不匹配。

使用控制台中的指纹更新我的assetlinks.json 解决了这个问题。

【讨论】:

【参考方案10】:

在我的例子中,adb shell dumpsys package d 显示 packageNameassetlinks.json 中的配置不正确。我在AndroidManifest.xml 中使用了manifest 标记的package 属性值,但我应该在build.gradle 文件中使用android.defaultConfig.packageId 值。

【讨论】:

【参考方案11】:

系统应用选择窗口两种情况

1) 用户通过进入设置>应用>齿轮图标>打开链接>选择一个应用>打开支持的链接>每次选择提示来更改设置相关的打开链接。

2) 用户未设置默认应用,并且在支持的应用链接之一中未启用自动验证

我认为在您的情况下启用了自动验证,因此请检查用户设置。

【讨论】:

【参考方案12】:

感谢这里的所有其他答案,我能够找到我的问题。尽管做的一切都是正确的。这是我的问题。

如果您的项目很大,您可能有多个 android 模块依赖项。检查合并的清单以查找所有带有意图过滤器的活动(使用 autoverify = true)。

这怎么会出错很简单。如果一个项目有多个自动验证 url,那么操作系统会尝试全部验证。即使一个失败,操作系统也无法验证每个 URL。

在您的主应用模块中打开清单文件,然后从底部选项卡中选择合并清单选项。现在检查右侧的清单源(列表)并手动查找每个库项目的清单文件。

就我而言,启用了第三方库的自动验证标志。我为期两天的搜索结束了。祝你好运。

【讨论】:

以上是关于Assetlinks.json 中的应用链接意图过滤器在 Android 上不起作用的主要内容,如果未能解决你的问题,请参考以下文章

AssetLinks 文件预期流量和故障场景

单击链接时未启动 InstantApp

Android 应用链接尝试验证随机主机并失败

如何在 PWA Android 应用中隐藏 URL 栏?

Android 深层链接 - 不显示意图选择器弹出窗口,强制打开应用

如何解决android原生应用程序中的意图重定向?