首页指南参考教程

深层链接

了解如何使用应用/通用链接从标准 Web URL 打开你的应用。


通用链接与标准深度链接不同,因为它们使用常规 HTTPS 链接将用户引导至应用中的特定路由。如果用户没有安装你的应用,该链接会将他们带到关联的网站。这使你可以发送带有链接的通知电子邮件,这些链接可以在桌面 Web 浏览器上无缝运行,同时在移动设备上打开应用中的内容。Android 将此概念称为应用链接,iOS 则将其称为通用链接。本指南专门讨论不使用自定义 URL 方案的通用链接。

¥Universal links are different from standard deep links as they use regular HTTPS links to direct users to a specific route in your app. If a user doesn't have your app installed, the link will take them to the associated website. This allows you to send notification emails with links that work seamlessly on desktop web browsers while opening the content in your app on mobile. Android refers to this concept as app links, and iOS refers to it as universal links. This guide specifically discusses universal links that do not use a custom URL scheme.

延迟深度链接可以通过 react-native-branch 来实现。

¥Deferred deep links can be implemented with react-native-branch.

在使用应用/通用链接之前,你必须为 Android 和 iOS 设置网站和应用之间的双向关联:

¥Before you can use an app/universal links, you have to setup the two-way association between the website and app for both Android and iOS:

  1. 原生应用验证:这需要某种形式的引用目标网站域 (URL) 的代码签名。

    ¥Native app verification: This requires some form of code signing that references the target website domain (URL).

  2. 网站验证:这需要在目标网站的 /.wellknown 目录中托管一个文件。

    ¥Website verification: This requires a file to be hosted on the target website in the /.well-known directory.

设置双向关联后,你必须在应用中设置链接的运行时路由。这是用 JavaScript 完成的,必须为每个路由进行配置,然后在 Web 和原生之间进行协调。Expo 为此提供了一个名为 Expo 路由 的全自动解决方案。

¥After the two-way association is setup, you have to setup the runtime routing of the link in your app. This is done in JavaScript and must be configured for every route, then coordinated between web and native. Expo offers a fully automated solution for this called Expo Router.

无法在 Expo Go 应用中测试通用链接。你需要创建一个 开发构建

¥Universal links cannot be tested in the Expo Go app. You need to create a development build.

iOS 上的通用链接

¥Universal links on iOS

iOS 上的通用链接需要付费 Apple 开发者账户,因为你必须关联完全合格的 Apple 开发者团队 ID。

¥Universal links on iOS require a paid Apple Developer account as you must associate your fully qualified Apple Developer Team ID.

苹果原生配置

¥Native Apple configuration

部署 apple-app-site-association (AASA) 文件后,你还必须将应用配置为使用关联的域:

¥After deploying your apple-app-site-association (AASA) file, you must also configure your app to use your associated domain:

expo.ios.associatedDomains 添加到 应用配置 中,并确保遵循 苹果指定的格式。确保你的 URL 中不包含协议 (https)。这是一个常见错误,会导致通用链接不起作用。

¥Add expo.ios.associatedDomains to your app config, and make sure to follow Apple's specified format. Make sure not to include the protocol (https) in your URL. This is a common mistake that will result in the universal links not working.

例如,如果关联网站为 https://expo.dev/,则应用链接为:

¥For example, if an associated website is https://expo.dev/, the app links are:

app.json
{
  "expo": {
    "ios": {
      "associatedDomains": ["applinks:expo.dev"]
    }
  }
}

使用 EAS Build 构建你的原生应用,以确保权利已向 Apple 注册。

¥Build your native app with EAS Build to ensure the entitlement is registered with Apple.

Manual native configuration

不使用 持续的原生生成 (npx expo prebuild) 的应用必须为其打包包标识符使用 手动配置 关联域功能。

¥Apps that don't use Continuous Native Generation (npx expo prebuild) must manually configure the Associated Domains capability for their bundle identifier.

如果你通过 苹果开发者控制台 启用,请务必在 ios/[app]/[app].entitlements 文件中添加以下权利:

¥If you enable through the Apple Developer Console, then be sure to add the following entitlements in your ios/[app]/[app].entitlements file:

<key>com.apple.developer.associated-domains</key>
<array>
  <string>applinks:expo.dev</string>
</array>

AASA 配置

¥AASA configuration

在网络端,你必须托管来自 /.well-known/apple-app-site-association 的配置文件(无扩展名)。此文件 JSON 指定你的 Apple 开发者团队 ID、Bundler ID 以及重定向到原生应用的受支持路径列表。

¥On the web-side, you have to host a config file from /.well-known/apple-app-site-association (with no extension). This file JSON specifies your Apple Developer Team ID, Bundler ID, and a list of supported paths to redirect to the native app.

你可以运行实验性 CLI 命令 npx setup-safari,自动将打包包标识符注册到你的 Apple 账户,为该 ID 分配权利,并在商店中创建 iTunes 应用条目。将打印本地设置,你可以跳过以下大部分内容。这是在 iOS 上开始使用通用链接的最简单方法。

¥You can run the experimental CLI command npx setup-safari to automatically register a bundle identifier to your Apple account, assign entitlements to the ID, and create an iTunes app entry in the store. The local setup will be printed and you can skip most the following. This is the easiest way to get started with universal links on iOS.

如果你使用 Expo 路由 构建网站(或其他现代 React 框架,如 Remix、Next.js 等),请在 public/.well-known/apple-app-site-association 中创建文件。旧版 Expo webpack 项目可以在 web/.well-known/apple-app-site-association 中创建该文件。

¥If you're using Expo Router to build your website (or another modern React framework like Remix, Next.js, and so on), create the file at public/.well-known/apple-app-site-association. Legacy Expo webpack projects can create the file at web/.well-known/apple-app-site-association.

public/.well-known/apple-app-site-association
{
  // This section enables Universal Links
  "applinks": {
    "apps": [],
    "details": [
      {
        // Example: "QQ57RJ5UTD.com.acme.myapp"
        "appID": "{APPLE_TEAM_ID}.{BUNDLE_ID}",
        // All paths that should support redirecting
        "paths": ["/records/*"]
      }
    ]
  },
  // This section enables Apple Handoff
  "activitycontinuation": {
    "apps": ["{APPLE_TEAM_ID}.{BUNDLE_ID}"]
  },
  // This section enable Shared Web Credentials
  "webcredentials": {
    "apps": ["{APPLE_TEAM_ID}.{BUNDLE_ID}"]
  }
}

此代码片段告诉 iOS,任何指向 https://www.myapp.io/records/* 的链接(具有与记录 ID 匹配的通配符)都应由具有匹配包标识符的应用直接打开。它是团队 ID 和应用包标识符的组合。团队 ID 可以在 Apple 开发者账户的成员详细信息下找到。

¥This snippet tells iOS that any links to https://www.myapp.io/records/* (with wildcard matching for the record ID) should be opened directly by the app with a matching bundle identifier. It is a combination of the Team ID and the app bundle identifier. The Team ID can be found under the membership details in the Apple Developer account.

activitycontinuationwebcredentials 对象是可选的,但建议使用。

¥The activitycontinuation and webcredentials objects are optional, but recommended.

设置 AASA 文件后,将网站部署到支持 HTTPS(大多数现代 Web 主机)的服务器。

¥After you have setup the AASA file, deploy your website to a server that supports HTTPS (most modern web hosts).

有关 AASA 格式的更多详细信息,请参阅 苹果的文档。Branch 提供了 AASA 验证器,它可以帮助你确认你的 AASA 已正确部署并且具有有效的格式。

¥See Apple's documentation for further details on the format of the AASA. Branch provides an AASA validator which can help you confirm that your AASA is correctly deployed and has a valid format.

* 通配符与域或路径分隔符(句点和斜杠)不匹配。

¥The * wildcard does not match domain or path separators (periods and slashes).

从 iOS 13 开始,支持新的 details 格式 允许你指定:

¥As of iOS 13, a new details format is supported which allows you to specify:

  • appIDs 而不是 appID,这使得更容易将多个应用与相同的配置关联起来

    ¥appIDs instead of appID, which makes it easier to associate multiple apps with the same configuration

  • components 数组,允许你指定片段、排除特定路径以及添加注释

    ¥an array of components, which allows you to specify fragments, exclude specific paths, and add comments

Here's an example AASA JSON from Apple's documentation
{
  "applinks": {
    "details": [
      {
        "appIDs": ["ABCDE12345.com.example.app", "ABCDE12345.com.example.app2"],
        "components": [
          {
            "#": "no_universal_links",
            "exclude": true,
            "comment": "Matches any URL whose fragment equals no_universal_links and instructs the system not to open it as a universal link"
          },
          {
            "/": "/buy/*",
            "comment": "Matches any URL whose path starts with /buy/"
          },
          {
            "/": "/help/website/*",
            "exclude": true,
            "comment": "Matches any URL whose path starts with /help/website/ and instructs the system not to open it as a universal link"
          },
          {
            "/": "/help/*",
            "?": {
              "articleNumber": "????"
            },
            "comment": "Matches any URL whose path starts with /help/ and which has a query item with name 'articleNumber' and a value of exactly 4 characters"
          }
        ]
      }
    ]
  }
}

要支持所有 iOS 版本,你可以在 details 密钥中提供上述两种格式,但我们建议首先放置更新的 iOS 版本的配置。

¥To support all iOS versions, you can provide both the above formats in your details key, but we recommend placing the configuration for more recent iOS versions first.

请注意,当你的应用首次安装以及从 App Store 安装更新时,iOS 会下载你的 AASA,但不会更频繁地刷新。如果你希望更改生产应用的 AASA 路径,则需要通过 App Store 发布完整更新,以便所有用户的应用重新获取你的 AASA 并识别新路径。

¥Note that iOS will download your AASA when your app is first installed and when updates are installed from the App Store, but it will not refresh any more frequently. If you wish to change the paths in your AASA for a production app, you will need to issue a full update via the App Store so that all of your users' apps re-fetch your AASA and recognize the new paths.

现在,移动设备上指向你网站的链接应该会打开你的应用。如果没有,请重新检查前面的步骤,以确保你的 AASA 有效、AASA 中指定了路径,并且你已在 苹果开发者控制台.txt 文件中正确配置了你的 App ID。打开应用后,请转到 处理你的应用的链接 部分,详细了解如何处理入站链接并向用户显示他们请求的内容。

¥Now, a link to your website on your mobile device should open your app. If it doesn't, re-check the previous steps to ensure that your AASA is valid, the path is specified in the AASA, and you have correctly configured your App ID in the Apple Developer Console. Once you have got your app opened, move to the Handling links into your app section for details on how to handle the inbound link and show the user the content they requested.

苹果智能横幅

¥Apple Smart Banner

如果用户没有安装你的应用,他们将被定向到该网站。你可以使用 苹果智能横幅 在页面顶部显示横幅,提示用户安装应用。该横幅仅在用户使用移动设备且未安装该应用时显示。

¥If a user doesn't have your app installed, they'll be directed to the website. You can use the Apple Smart Banner to show a banner at the top of the page that prompts the user to install the app. The banner only shows if the user is on a mobile device and doesn't have the app installed.

要启用横幅,请将以下元标记添加到你网站的 <head>,并将 {ITUNES_ID} 替换为你应用的 iTunes ID:

¥To enable the banner, add the following meta tag to the <head> of your website, replacing {ITUNES_ID} with your app's iTunes ID:

<meta name="apple-itunes-app" content="app-id={ITUNES_ID}" />

如果你在设置横幅时遇到问题,请运行以下命令来自动为你的项目生成元标记:

¥If you're having trouble setting up the banner, run the following command to automatically generate the meta tag for your project:

Terminal
npx setup-safari

如果你正在构建 使用 Expo Router 静态渲染网站,请将此 HTML 标记添加到 app/+html.js 文件 中的 <head> 组件中。

¥If you're building a statically rendered website with Expo Router, then add this HTML tag to the <head> component in your app/+html.js file.

app/+html.js
export default function Root({ children }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta httpEquiv="X-UA-Compatible" content="IE=edge" />

        <meta name="apple-itunes-app" content="app-id={ITUNES_ID}" />

        

{/* Other head elements... */}


      </head>
      <body>{children}</body>
    </html>
  );
}

下次部署网站时,当你在未安装应用的移动设备上访问网站时,应该会出现横幅。

¥Next time you deploy your website, the banner should appear when you visit it on a mobile device that doesn't have your app installed.

Android 上的深层链接

¥Deep links on Android

在 Android 上实现深度链接(无需自定义 URL 方案)比在 iOS 上更简单。你需要将 intentFilters 添加到 应用配置android 部分。以下基本配置将使你的应用显示在标准 Android 对话框中,作为处理任何指向 myapp.io 的记录链接的选项:

¥Implementing deep links on Android (without a custom URL scheme) is somewhat simpler than on iOS. You need to add intentFilters to the android section of your app config. The following basic configuration will cause your app to be presented in the standard Android dialog as an option for handling any record links to myapp.io:

app.json
{
  "expo": {
    "android": {
      "intentFilters": [
        {
          "action": "VIEW",
          "autoVerify": true,
          "data": [
            {
              "scheme": "https",
              "host": "*.myapp.io",
              "pathPrefix": "/records"
            }
          ],
          "category": ["BROWSABLE", "DEFAULT"]
        }
      ]
    }
  }
}

安卓应用链接

¥Android App Links

可能需要指向你的域的链接始终打开你的应用(而不向用户显示可以选择浏览器或不同处理程序的对话框)。你可以使用 Android 应用链接来实现此目的,它使用与 iOS 上的通用链接类似的验证过程。

¥It may be desirable for links to your domain to always open your app (without presenting the user a dialog where they can choose the browser or a different handler). You can implement this with Android App Links, which use a similar verification process as Universal Links on iOS.

在 public/.well-known/assetlinks.json(对于旧版 Expo webpack 网站为 web/.well-known/assetlinks.json)创建用于网站验证的 JSON 文件(也称为 数字资源链接 文件),并收集以下信息 :

¥Create a JSON file for the website verification (also known as digital asset links file) at public/.well-known/assetlinks.json (or web/.well-known/assetlinks.json for legacy Expo webpack websites), and collect the following information:

  • package_name:你的应用的 Android 应用 ID(例如 com.bacon.app)。这可以在 expo.android.package 下的 app.json 文件中找到。

    ¥package_name: The Android application ID of your app (for example, com.bacon.app). This can be found in the app.json file under expo.android.package.

  • sha256_cert_fingerprints:应用签名证书的 SHA256 指纹。这可以通过以下两种方式之一获得:

    ¥sha256_cert_fingerprints: The SHA256 fingerprints of your app's signing certificate. This can be obtained in one of two ways:

    1. 使用 EAS Build 构建 Android 应用后,运行 eas credentials -p android 并选择你想要获取指纹的配置文件。指纹将列在 SHA256 Fingerprint 下。

      ¥After building an Android app with EAS Build, run eas credentials -p android and select the profile you wish to obtain the fingerprint for. The fingerprint will be listed under SHA256 Fingerprint.

    2. 通过访问“发布”>“设置”>“应用签名”下的 Play 管理中心 开发者账户。如果这样做,那么你还将在同一页面上找到你的应用的正确数字资源链接 JSON 片段。该值看起来像 14:6D:E9:83...

      ¥By visiting the Play Console developer account under Release > Setup > App Signing. If you do, then you'll also find the correct Digital Asset Links JSON snippet for your app on the same page. The value will look like 14:6D:E9:83...

public/.well-known/assetlinks.json
[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "{package_name}",
      "sha256_cert_fingerprints": [
        // Supports multiple fingerprints for different apps and keys
        "{sha256_cert_fingerprints}"
      ]
    }
  }
]

在设备上安装原生应用将触发 安卓应用验证 进程,该过程最多可能需要 20 秒。打开应用后,请转到 处理你的应用的链接 部分,详细了解如何处理入站链接并向用户显示他们请求的内容。

¥Installing the native app on a device will trigger the Android app verification process, which can take up to 20 seconds. Once you have got your app opened, move to the Handling links into your app section for details on how to handle the inbound link and show the user the content they requested.

Manual native configuration

如果你不使用 EAS 来管理代码签名,则可以通过手动构建和提交应用来找到 sha256_cert_fingerprints,然后访问“发布”>“设置”>“应用签名”下的 谷歌游戏控制台 开发者账户;如果这样做,那么你还将在同一页面上找到适合你的应用的正确数字资源链接 JSON 片段。该值将类似于 14:6D:E9:83...。将此值复制到 public/.well-known/assetlinks.json 文件中。

¥If you're not using EAS to manage code signing, you can find the sha256_cert_fingerprints by building and submitting your app manually, then visiting the Google Play Console developer account under Release > Setup > App Signing; if you do, then you'll also find the correct Digital Asset Links JSON snippet for your app on the same page. The value will look like 14:6D:E9:83.... Copy this value into your public/.well-known/assetlinks.json file.

调试

¥Debugging

Expo CLI 使你能够在不部署网站的情况下测试通用链接。利用 --tunnel 功能,你可以将你的开发服务器转发到公开可用的 https URL。

¥Expo CLI enables you to test your universal links without deploying a website. Utilizing the --tunnel functionality, you can forward your dev server to a publicly available https URL.

  1. 设置环境变量 EXPO_TUNNEL_SUBDOMAIN=my-custom-domain,其中 "my-custom-domain" 是你将在开发过程中使用的唯一字符串。这将确保你的隧道 URL 在开发服务器重新启动时保持一致。

    ¥Set the environment variable EXPO_TUNNEL_SUBDOMAIN=my-custom-domain where "my-custom-domain" is a unique string that you will use during development. This will ensure that your tunnel URL is consistent across dev server restarts.

  2. 如上所述设置通用链接,但这次使用 Ngrok URL:my-custom-domain.ngrok.io

    ¥Setup universal links as described above, but this time using an Ngrok URL: my-custom-domain.ngrok.io

  3. 使用 --tunnel 标志启动你的开发服务器:

    ¥Start your dev server with the --tunnel flag:

Terminal
npx expo start --tunnel --dev-client
  1. 在你的设备上编译开发版本:

    ¥Compile the development build on your device:

Terminal
# Build your native Android project
npx expo run:android

# Build your native iOS project
npx expo run:ios

故障排除

¥Troubleshooting

  • 阅读 Apple 的 关于调试通用链接的官方文档

    ¥Read Apple's official documentation on debugging universal links.

  • 使用 验证器工具.conf 确保你的 Apple 应用站点关联文件有效。

    ¥Ensure your apple app site association file is valid by using a validator tool.

  • 确保你的网站通过 HTTPS 提供服务。

    ¥Ensure your website is served over HTTPS.

  • 未压缩的 apple-app-site-association 文件不能是 大于 128kb

    ¥The uncompressed apple-app-site-association file cannot be larger than 128kb.

  • 验证 Android 应用链接

    ¥Verify Android app links

  • 确保两个网站验证文件均通过 content-type application/json 提供。

    ¥Ensure both website verification files are served with content-type application/json.

  • Android 验证最多可能需要 20 秒才能生效。

    ¥Android verification may take up to 20 seconds to take effect.

  • 如果你更新 Web 文件,请重建原生应用以触发提供者端(Google、Apple)的服务器更新。

    ¥If you update your web files, rebuild the native app to trigger a server update on the vendor side (Google, Apple).

何时不使用深层链接

¥When to not use deep links

这是在应用中设置深层链接的最简单方法,因为它需要最少的配置。

¥This is the easiest way to set up deep links in your app because it requires a minimal amount of configuration.

主要问题是,如果用户没有安装你的应用并通过其自定义方案链接到你的应用,他们的操作系统将指示该页面无法打开,但不会提供更多信息。这不是一次很棒的经历。在浏览器中没有办法解决这个问题。

¥The main problem is that if the user does not have your app installed and follows a link to your app with its custom scheme, their operating system will indicate that the page couldn't be opened but not give much more information. This is not a great experience. There is no way to work around this in the browser.

此外,许多消息传递应用不会使用自定义方案自动链接 URL。例如,exp://u.expo.dev/[project-id]?channel-name=[channel-name]&runtime-version=[runtime-version] 可能仅在浏览器中显示为纯文本,而不是链接 (exp://u.expo.dev/[project-id]?channel-name=[channel-name]&runtime-version=[runtime-version])。

¥Additionally, many messaging apps do not autolink URLs with custom schemes. For example, exp://u.expo.dev/[project-id]?channel-name=[channel-name]&runtime-version=[runtime-version] might just show up as plain text in your browser rather than as a link (exp://u.expo.dev/[project-id]?channel-name=[channel-name]&runtime-version=[runtime-version]).

Gmail 就是一个例子,它从大多数应用的链接中删除了 href 属性,使用的一个技巧是链接到常规 HTTPS URL 而不是应用的自定义方案,这将打开用户的网络浏览器。浏览器通常不会删除 href 属性,因此你可以在线托管一个文件,将用户重定向到应用的自定义方案。

¥An example of this is Gmail which strips the href property from the links of most apps, a trick to use is to link to a regular HTTPS URL instead of your app's custom scheme, this will open the user's web browser. Browsers do not usually strip the href property so you can host a file online that redirects the user to your app's custom schemes.

你可以链接到 https://example.com/redirect-to-app.html,而不是链接到 example://path/into/app,而 redirect-to-app.html 将包含以下代码:

¥Instead of linking to example://path/into/app, you could link to https://example.com/redirect-to-app.html and redirect-to-app.html would contain the following code:

<script>window.location.replace("example://path/into/app");</script>
Expo 中文网 - 粤ICP备13048890号