universal links 设置:iOS与Android的网站端

universal links 设置:部署apple-app-site-association和assetlinks.json,说明服务器规则、检查与回退方案。

目录

universal links 设置的网站部分,就是你自己托管的两个JSON文件:iOS使用apple-app-site-association,Android使用assetlinks.json。当有人点击普通的https://链接时,它们能让应用代替网站打开该链接。两个文件都放在应用所处理的每个域名的/.well-known/下,都必须通过HTTPS提供且不能有重定向,并且各自指定了允许打开你网址的应用。应用也需要相应的设置(iOS上是授权,Android上是intent过滤器),下面会在每个文件旁边给出。

universal links与Android App Links的工作方式

两个系统都在网站和应用之间建立双向连接:应用声明它处理哪些域名,网站则确认这一点。Apple将universal links描述为标准的HTTP或HTTPS链接,因此同一个URL既可用于网站,也可用于应用;没有安装应用的用户则会在浏览器中打开网页(Apple)。按照Google的说法,Android App Links基于与其他深层链接相同的intent机制,但增加了一个验证步骤,需要你在网站上放置Digital Asset Links文件(Android开发者)。

iOS universal links Android App Links
网站上的文件 apple-app-site-association assetlinks.json
位置 https://<domain>/.well-known/apple-app-site-association https://<domain>/.well-known/assetlinks.json
应用中的声明 Associated Domains授权,applinks:<domain> 带android:autoVerify="true"的intent过滤器
识别应用的方式 Team ID加Bundle ID 包名加签名证书指纹
检查时机 安装时,通过Apple的CDN 安装时;Android 15及更高版本还会在后台检查
通用链接和 App Links 需要两端配合:应用声明域名(Associated Domains 或带 autoVerify 的 intent filter),网站在 .well-known 下提供文件(apple-app-site-association 或 assetlinks.json)

“深层链接”是更宽泛的术语。普通的深层链接可能使用自定义scheme或未经验证的https://链接;universal links和App Links则是经过验证的那一类。

iOS文件:apple-app-site-association

创建一个名为apple-app-site-association的文件(没有扩展名),列出你的应用标识符,以及应用应当打开的URL模式。下面是Apple文档中示例结构的精简版:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["ABCDE12345.com.example.app"],
        "components": [
          { "/": "/buy/*", "comment": "Open URLs that start with /buy/ in the app." },
          { "/": "/help/website/*", "exclude": true, "comment": "Keep these in the browser." }
        ]
      }
    ]
  }
}

appIDs的值是应用标识符前缀(你的Team ID),加一个点,再加Bundle ID。components中的每一项匹配URL的一部分,"exclude": true表示匹配的URL不要在应用中打开(Apple,Supporting associated domains)。Apple也接受较旧的格式,使用appID和paths;其调试说明提醒不要混用两种格式(TN3155)。

将文件托管在https://<完整域名>/.well-known/apple-app-site-association,使用有效证书且不要重定向。Apple文档中的三条规则常会让人踩坑:

  • 每个子域名都需要在应用中有自己的条目。位于example.com的文件服务于applinks:example.com和applinks:*.example.com,而像www.example.com这样的具体子域名需要它自己的文件。
  • 该文件必须可以从任何IP地址、以任何用户代理访问。防火墙、机器人过滤器或登录墙返回的403或404,会阻止Apple的服务器缓存它。
  • 自iOS 14起,设备不再从你的服务器获取该文件。由Apple的CDN获取并缓存它,设备大约每周检查一次更新,而且无法直接使缓存失效;重新安装应用会下载更新的副本(TN3155)。

开发期间,你可以在授权条目中添加?mode=developer(applinks:example.com?mode=developer),这样设备会直接从你的服务器读取文件,而不是从Apple的CDN读取。

Android文件:assetlinks.json

assetlinks.json是一个语句数组,其中写明你的包名,以及签名应用的证书的SHA-256指纹。下面是Google针对一个应用的示例:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

请把包名和指纹替换成你自己的。要求来自Google的指南(2026年10月23日更新):

  • 在https://<domain>/.well-known/assetlinks.json提供,内容类型为application/json。
  • 即使应用的intent过滤器也声明了http,仍然使用HTTPS。
  • 不能有重定向,无论是301还是302。
  • 在应用处理的每个主机域名上都要发布。
  • 一个文件可以列出多个应用,sha256_cert_fingerprints字段可以接受多个指纹,例如调试版和正式版的指纹。

如果你使用Play应用签名,你在本地keytool得到的指纹通常与用户设备上的指纹不一致。Google建议从Play Console的“版本 > 设置 > 应用签名”中获取正确的JSON片段。

应用端是带autoVerify的intent过滤器。这是Android文档中的写法:

<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="http" />
    <data android:scheme="https" />
    <data android:host="www.example.com" />
</intent-filter>

Android会验证此类过滤器中的每个主机名,而通配符主机(如*.example.com)需要根域名example.com上的文件(Android开发者)。在Android 15及更高版本上,验证还会定期运行,文件的改动最长可能需要七天才能生效;在Android 14及更低版本上,文件只在安装或更新时读取(Android开发者)。

服务器检查清单

两个文件通常因为同样几个原因而失败,因此可以对服务器做一次检查,同时覆盖两者:

检查项 原因 测试方法
HTTPS 两个平台都要求,Apple还要求有效证书 在浏览器中打开该URL
没有301或302 两种文件都不支持重定向 curl -sI应显示200
iOS:对所有IP和用户代理公开 Apple的CDN需要获取文件,防火墙或机器人过滤器会阻止它 curl -A "MyAgent-Bot/1.0" <url>能返回文件
Android:Content-Type: application/json Google将其列为要求 curl -sI查看响应头
你列出的每个域名和子域名都有相同的文件 每个主机都是单独验证的 逐个主机运行检查

关于内容类型,两个文件都以application/json提供,可以让设置保持一致。Apple的文档没有说明iOS文件的内容类型,因此这部分属于你的选择。下面是一个静态的nginx示例:

location = /.well-known/apple-app-site-association {
    default_type application/json;
}
location = /.well-known/assetlinks.json {
    default_type application/json;
}

如何检查它是否生效

先从外部检查文件,再在设备上检查实际行为。以下是Apple在TN3155中给出的调试步骤:

  1. 运行curl -v https://<domain>/.well-known/apple-app-site-association,确认返回200和JSON内容,而不是301、302、403或404。
  2. 在Mac上,sudo swcutil dl -d <domain>用于检查文件能否下载,sudo swcutil verify -d <domain> -j <path-to-JSON> -u <URL>用于检查某个URL是否匹配模式。
  3. 在iPhone上,把链接粘贴到备忘录应用中并长按。如果配置正确,“在应用中打开”和“在浏览器中打开”两个选项都会出现。

对于Android,Google在Android 12及更高版本上的手动验证方法如下(如果应用的目标版本低于Android 12,先运行adb shell am compat enable 175408749 com.example):

adb shell pm set-app-links --package com.example 0 all
adb shell pm verify-app-links --re-verify com.example
# 等待几分钟,然后:
adb shell pm get-app-links com.example

输出会列出每个域名及其状态,例如verified或legacy_failure。Google还提供了Statement List Generator和Tester(Digital Asset Links工具),用于测试已有的语句文件。如需更完整的测试流程,见移动网站测试清单。

哪些情况下链接不会打开应用

在iOS上,在浏览器地址栏中输入URL永远不会打开应用,因为那是浏览器内的直接导航;如果用户已经在你的域名上,同域名的链接也会留在Safari中(TN3155)。对于登录按钮等流程,Apple的解决办法是使用另一个子域名,并为它配置独立的applinks条目和AASA文件,这样系统就会把这次点击视为离开网站。

应用内浏览器需要单独测试。Apple表示,在浏览器应用或WKWebView中点击的链接可以打开你的应用,但同时也说明第三方浏览器自行决定是否启用universal links(TN3155中的“Universal links may not be enabled in every web browser”),而且如果某个应用通过自己的open(_:)调用打开你的链接,它不会反过来打开你的链接(Apple)。某个社交应用的浏览器是否会把链接交给你的应用,平台文档中没有说明,因此请在真机上测试你关心的每一个应用。

作为回退的智能应用横幅

智能应用横幅是网页上仅限iOS的提示:在你希望显示它的每个页面的<head>中添加一个meta标签。根据Apple的说明,如果已安装应用,它会打开应用;如果未安装,则链接到App Store。

<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-argument=https://example.com/buy/42">

app-id是必填项,可选的app-argument会把一个URL传给应用,使其打开对应的界面。Apple列出了两个限制:横幅不会出现在框架(frame)内,也不会出现在iOS模拟器中。

如果你没有发布原生应用,就不需要这两个文件;渐进式网页应用是直接从浏览器安装的。

在手机尺寸下检查回退页面

所有没有安装应用的人,以及每个没有成功跳转到应用的链接,最终都会落到你的网页上,因此该页面必须在手机上正常工作。Mobile View Extension会以手机的用户代理、屏幕尺寸和像素比重新加载标签页,因此你可以在多种尺寸下看到回退页面的真实移动版本;也可以同时使用Chrome的设备模拟。但它无法测试应用跳转本身:它运行的是桌面版Chrome,没有触摸事件,也没有已安装的应用,因此链接处理需要用iPhone或Android手机,或iOS模拟器和Android模拟器。如果没有iOS硬件,见没有iPhone如何测试iPhone上的网站。

常见问题

universal links和深层链接有什么区别?

深层链接是宽泛的类别;universal links是Apple经过验证的那一类,基于标准的HTTP或HTTPS链接。深层链接也可以使用自定义URL scheme,它不与你控制的网站绑定。Android App Links是Android上经过验证的形式,在普通深层链接的基础上增加了Digital Asset Links检查。

apple-app-site-association应该放在哪里?

放在https://<domain>/.well-known/apple-app-site-association,不带文件扩展名,通过HTTPS提供,使用有效证书,并且不能有重定向。应用列出的每个子域名都需要自己的一份副本。

为什么我的universal link打开的是Safari而不是应用?

常见原因包括:重定向、文件返回403或404、缺少子域名条目,或点击的是同域名链接。Apple在TN3155中列出了这些情况;在地址栏中输入URL,或在Safari中浏览时点击同一域名的链接,都会让用户停留在浏览器中。先用curl -v检查文件。

两个文件都需要吗?

你只需要为你发布应用的每个平台提供对应的文件。同时拥有iOS应用和Android应用的网站两者都要提供,且两者彼此独立。

用手机视图查看你的下一个网站。

添加扩展,在你正在使用的标签页中直接打开设备预览。