Android App Links 验证失败:用 adb 五分钟定位问题
从 Android 12 起,域名验证未通过的 App Link 会在浏览器而非你的应用中打开——静默发生,而且并非每台设备都一样。这份 adb 排查清单能快速找到原因,包括大多数事故背后的 Play 签名密钥不匹配问题。
应用装着,链接却打开了 Chrome
它通常以工单而非报错的形式出现。用户点了指向你域名的链接,应用就在手机上,打开的却是 Chrome。按 Android 文档的说法,从 Android 12 起,https 链接只有在系统于安装时验证过你的域名后才会打开应用——而验证失败时是静默失败。没有崩溃,没有提示,仪表盘里什么也看不到。
有两个特性让排查格外痛苦。验证按域名进行:example.com 可能已验证,promo.example.com 却悄悄没有。它还按设备进行:同一个构建在 Pixel 上通过,在三星手机上却失败——三星开发者论坛的帖子里反复出现这种组合。如果你正处在事故当中,直接跳到下面的诊断部分。
两个域名,两种裁决
安装时到底发生了什么
应用安装或更新时,Android 会读取每个用 autoVerify 声明的域名,并逐一抓取 https://你的域名/.well-known/assetlinks.json。按 Android 文档,该文件必须以 HTTPS 直接返回 200,content type 为 application/json——验证器不跟随重定向。结果按域名缓存,这就是为什么一个子域名已验证、它的兄弟却没有。
文件里的 sha256_cert_fingerprints 必须匹配设备上 APK 的签名证书。头号陷阱来了:启用 Play App Signing 后,那个证书是 Google 的应用签名密钥——不是你的上传密钥。本地 keystore 的指纹能完美验证手动安装的构建,却会让每一次来自 Play 商店的安装失败。「在我设备上是好的」的报告里,一半都追溯到这里。
开始前还要知道一点:裁决会被缓存。修好服务器上的 JSON,对已经失败的手机毫无作用,直到验证再次运行——幸好这可以强制触发。
应用安装或更新
Android 读取每个用 autoVerify 声明的域名
为每个域名抓取 assetlinks.json
/.well-known/assetlinks.json
- 01
通过 HTTPS 直接返回 200
HTTP 200
失败原因: 301 或 302 重定向、404、登录墙或机器人校验
- 02
以 JSON 格式返回
content-type: application/json
失败原因: text/html 或 text/plain,即使正文有效
- 03
包名已列出
com.example.app
失败原因: 数组里缺少某个 flavor 或包名
- 04
指纹与已安装的应用一致
sha256_cert_fingerprints
失败原因: 只有上传密钥,没有 Play 签名密钥
verified:链接打开应用
按域名保存在这台设备上
none:链接打开浏览器
静默发生,没有崩溃,仪表盘里也毫无痕迹
裁决会被缓存。文件修好后,已经失败的手机在验证再次运行前不会有任何变化,所以要强制重新验证。
五分钟诊断
接上任意一台装有应用的 Android 12+ 设备,按顺序执行。多数事故在第三步就能解决。
读取验证状态
adb shell pm get-app-links com.example.app这条命令打印应用声明的每个域名及其状态。verified 表示握手通过;none 表示验证器从未批准该域名——把用户送去 Chrome 的正是它。多用户设备上,也要检查输出底部按用户划分的部分。
像验证器那样抓取 assetlinks.json
curl -sI https://example.com/.well-known/assetlinks.json你要看到直接的 200。任何 301 或 302 都会让验证失败——按 Android 文档,验证器不跟随重定向。确认 content-type 是 application/json,然后抓取正文,亲眼核对包名和指纹。/.well-known/ 前面的反爬或登录墙同样算失败。
对照 Play 签名密钥核对指纹
Play Console → App integrity → App signing key certificate打开 Play Console 的这个页面,把上面的 SHA-256 和你的 JSON 放在一起。必须逐字节一致。如果文件里是上传密钥的指纹,问题就找到了——加入 Play 签名密钥指纹;如果还在 Play 商店之外分发构建,两个都保留。
强制重新验证
adb shell pm verify-app-links --re-verify com.example.app修好服务器端后,让设备再试一次。验证器是异步运行的:等几秒,重复第一步,观察 none 变成 verified。部分三星设备的状态要重启后才会变——三星开发者论坛报告过这一模式。
像真实点击一样触发 intent
adb shell am start -a android.intent.action.VIEW -d "https://example.com/promo"这是端到端测试。已验证的域名会直接打开应用,没有选择器。如果出现浏览器或选择弹窗,说明状态还没翻转——先复查第一步,再下结论说修复失败。
如果不想在事故中肉眼核对 JSON,我们的 链接校验工具 会抓取你的 assetlinks.json,一次性检查状态码、content type 和指纹格式。
常见元凶
五个原因覆盖了我们见过的几乎所有报告。左边原因,右边修法。
手动安装的构建
用你的上传密钥签名
assetlinks.json
文件中列出的指纹
匹配:verified
从 Google Play 安装
用 Google 的应用签名密钥签名
assetlinks.json
文件中列出的指纹
不匹配:none
修法:从 Play Console → App integrity → App signing key certificate 添加 SHA-256。如果还分发用上传密钥签名的构建,两个指纹都保留。
JSON 里是上传密钥指纹,而不是 Play 签名密钥
从 Play Console → App integrity → App signing key certificate 复制 SHA-256。如果还分发上传密钥签名的构建,两个指纹都保留。
assetlinks.json 返回重定向或 404
在每个声明的主机上直接以 /.well-known/assetlinks.json 提供文件。对验证器来说,www 和裸域是两个不同的域名。
错误的 content type,如 text/html 或 text/plain
配置服务器或 CDN 对该路径返回 application/json。正文再正确,头错了照样失败。
多个 flavor 或包名,文件里缺了一个
这个文件是数组:每个包名一条声明,各带自己的指纹。缺了哪个 flavor 就只有那个失败,在 QA 里看起来像随机故障。
修好 JSON 后三星设备仍停在 none
部分三星机型的延迟验证在三星开发者论坛是常客。先强制重新验证,再重启设备,然后才下别的结论。
Android 15 和 16 改了什么
最近两个版本把标准朝同一个方向推进:受支持的路径是经过验证的 https App Links,其余的路都在收窄。
按平台发行说明,加入了 Dynamic App Links:域名关联可以在不发布新 APK 的情况下更新,缩短了从修好 JSON 到设备生效之间的周期。
按平台发行说明,收紧了自定义 URI scheme 的验证方式。如果你的流程还依赖 myapp:// 这类 scheme,把它们当作遗留方案,把入口迁到已验证的 https 链接上。
智能链接的诚实定位
智能链接在服务器上完成路由,先于上述所有机制:有人打开 Appy 链接时,重定向读取设备信息,把 Android、iOS 和桌面访客送往不同目的地。这套路由在所有套餐可用,也不依赖设备端验证——因为它发生在操作系统看到你的域名之前。
也要说清它不能做什么:智能链接无法绕过 App Links 验证。重定向最终落在你的 https 域名上,打开应用还是浏览器,仍由那个 verified 或 none 的状态决定。它在事故中给你的是一扇可控的前门——修 assetlinks.json 期间,把 Android 流量指向 Play 商店页或你的网站,之后再把目的地改回来,已印刷的东西一个都不用动,因为动态二维码在印刷后仍可编辑。分析数据还会告诉你这段时间有多少 Android 流量撞上了坏掉的路径。
无论如何都要把验证修好。Pro 上的深度链接目的地、Enterprise 上跨越安装间隙的延迟深度链接都值得拥有——但它们建立在一份正常工作的 assetlinks.json 之上,而不是替代它。
有人点击你的链接
appy.to/promo
服务器端
重定向识别设备
Android、iOS 和桌面端分别前往不同目的地,所有套餐均可用
iOS 和桌面端:各自的目的地
手机端
Android 落到你的 https 域名
操作系统这时才看到你的域名
手机端
Android 按验证状态处理
修复 assetlinks.json 期间
把 Android 流量指向 Play 商店页面或你的网站,修好后再切回来。已印刷的二维码依然有效。
常见问题
为什么同一条链接在一台设备上正常,在另一台上不行?
验证在每台设备的安装时各自运行,所以每部手机都带着自己缓存的裁决。安装时的网络波动、行为不同的 OEM 验证器——三星是其开发者论坛上被报告最多的案例——或早于你修复 JSON 的安装,都会让同一构建呈现不同状态。
需要发应用更新才能修复吗?
通常不需要。如果 manifest 已用 autoVerify 声明了域名,故障就在 JSON 文件或指纹里,都在服务器端。修好文件、强制重新验证,已安装的构建就会开始打开链接。只有域名从未在 manifest 里声明时才需要更新。
智能链接能绕过 App Links 验证吗?
不能——对任何相反的说法都要警惕。重定向在服务器端选择目的地,但访客一落到你的 https 域名,操作系统就照常应用同样的验证状态。智能链接改变的是验证坏掉期间你能做什么——导向商店或网页——而不是它坏没坏。
验证多久会自己重试?
按 Android 文档,验证器会重试失败的域名,并在应用更新时重新运行,但时间表没有保证,各 OEM 也不同。实际上是数小时到数天。用 adb 强制重新验证,或重装应用,都比干等快。
继续探索
2026 年最佳深度链接工具:一份客观对比
Branch、AppsFlyer OneLink、Adjust、Airbridge、Kochava、Singular、Bitly、Dub、onelink.to 和 Appy,全部按各家官网的价格页和文档核对:深度链接、延迟深度链接、归因、二维码、AI 助手、价格和接入成本。
Branch.io 替代方案:不用绑卡,没有超额账单,链接不会过期
Branch 已经取消了免费套餐。现在光是试用就要交出信用卡,之后自动转为每月 $39、超额不封顶,自定义域名每月 $199。380 天没人点击的链接会过期。下面是完整情况,以及小团队改用什么。
Airbridge 2026 年改价:免费套餐变成了 30 天试用
Airbridge 曾宣传 Core 免费额度和免费 DeepLink 套餐,如今定价页写的是 30 天试用、之后每月 $40 起。本文整理时间线,以及按旧条件注册的用户需要检查什么。
想看更多内容?浏览 博客全部主题.