跳到主要内容
版本:v2

使用 Universal Links 和 App Links 进行深度链接

平台:iOS、Android

Universal links (iOS) 和 App Links (Android) 提供了将用户直接带到原生应用内特定内容的能力(通常称为深度链接)。

当用户点击深度链接时,用户会被直接引导到您的应用中,而无需先通过设备的 Web 浏览器或网站路由。如果应用未安装,则用户会被导向网站。如果用户直接导航到网站,他们将停留在网站上。这使得深度链接成为为 Web、iOS 和 Android 构建的跨平台应用的绝佳功能:无缝的移动体验,并优雅地回退到网站。

优势:

  • 安全:Universal/App Links 使用 HTTPS URL 链接到您拥有的网站域名,确保没有其他应用可以使用您的链接。
  • 无缝体验:一个 URL 同时适用于您的网站和应用,确保用户能够成功访问他们想要的内容而不会出错。
  • 提高参与度:链接可以从电子邮件客户端、搜索引擎结果等打开。

演示视频

以下是实际效果。在此示例中,用户已安装原生应用。他们从电子邮件中点击应用链接,直接被带入应用本身。首先,点击根链接 (https://beerswift.app),将用户带到主应用页面。接下来,点击深度链接 (https://beerswift.app/tabs/tab3),将用户带到 Tab3 页面。

前提条件

  • 一个预先配置好的 Capacitor 应用
  • 对于 iOS,需注册 Apple Developer Program。

为了说明目的,将使用 https://beerswift.app 作为 Web 应用链接。

使用 Capacitor App API 进行深度链接路由

当点击深度链接后打开原生应用时,移动操作系统不会自动知道将用户路由到哪里。这必须在应用启动时使用 Capacitor App API 在应用内部实现。

如果您的网站和应用路径不匹配,您将需要实现更高级的 URL 模式匹配(参见 本指南 中的示例)。不过,如果您的移动应用和 Web 应用使用相同的代码库,这非常简单——只需重定向到相同的 URL 即可。以下示例基于此假设。

Angular

路由应在 app.component.ts 中实现。首先从 Angular 导入 NgZoneRouter,然后从 Capacitor 导入 App

import { Component, NgZone } from '@angular/core';
import { Router } from '@angular/router';
import { Plugins } from '@capacitor/core';
const { App } = Plugins;

接下来,将 RouterNgZone 添加到构造函数中:

constructor(private router: Router, private zone: NgZone) {
this.initializeApp();
}

最后,监听 appUrlOpen 事件,并在找到深度链接时进行重定向:

initializeApp() {
App.addListener('appUrlOpen', (data: any) => {
this.zone.run(() => {
// 示例 url: https://beerswift.app/tabs/tab2
// slug = /tabs/tab2
const slug = data.url.split(".app").pop();
if (slug) {
this.router.navigateByUrl(slug);
}
// 如果不匹配,则不执行任何操作 - 让常规路由
// 逻辑接管
});
});
}

React

React 有多种选择。一种方法是将 App API 监听器功能包装在一个新组件中,然后将其添加到 App.tsx 中。首先创建 AppUrlListener.tsx,然后导入 React Router 的 useHistory hook 以及 Capacitor App API:

import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { Plugins } from '@capacitor/core';
const { App: CapApp } = Plugins;

接下来,定义 AppUrlListener 组件,监听 appUrlOpen 事件并在找到深度链接时进行重定向:

const AppUrlListener: React.FC<any> = () => {
let history = useHistory();
useEffect(() => {
CapApp.addListener('appUrlOpen', (data: any) => {
// 示例 url: https://beerswift.app/tabs/tab2
// slug = /tabs/tab2
const slug = data.url.split('.app').pop();
if (slug) {
history.push(slug);
}
// 如果不匹配,则不执行任何操作 - 让常规路由
// 逻辑接管
});
}, []);

return null;
};

export default AppUrlListener;

App.tsx 中,导入新组件:

import AppUrlListener from './pages/AppUrlListener';

然后将其添加到 IonReactRouter 中(或您的应用引导的任何位置,只需确保 History hook 可用即可):

const App: React.FC = () => {
return (
<IonApp>
<IonReactRouter>
<AppUrlListener></AppUrlListener>
<IonRouterOutlet>
<Route path="/home" component={Home} exact={true} />
<Route exact path="/" render={() => <Redirect to="/home" />} />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
};

Vue

VueJS 提供了一个名为 Vue Router 的官方路由系统,可与 Vue 原生集成。要使用 Vue Router 设置深度链接,请从用于配置所有路由的文件开始(通常是 routes.js 或类似文件)。

首先我们从 plugins 导入 capacitor App,以及 VueVueRouter

import { Plugins } from '@capacitor/core';
const { App } = Plugins;
import Vue from 'vue';
import VueRouter from 'vue-router';

接下来,使用 Vue Router 配置您的路由(更多信息请参见 Vue Router 入门)。

const router = new VueRouter({
routes: [],
});

建议使用 mode: history,这样就不需要处理 #

让 Vue 知道您正在使用 Vue Router,并在 Vue 中注册路由器:

const VueApp = new Vue({
router,
}).$mount('#app');

最后,我们需要为深度链接注册我们的应用。为此,我们在 Capacitor App 上添加一个 appUrlOpen 事件监听器。Capacitor 会捕获它,然后我们将其交给 Vue Router 导航到请求的页面。

App.addListener('appUrlOpen', function (data) {
// 示例 url: https://beerswift.app/tabs/tabs2
// slug = /tabs/tabs2
const slug = data.url.split('.app').pop();

// 只有在存在 slug 时才推送到路由
if (slug) {
router.push({
path: slug,
});
}
});

创建网站关联文件

为了允许 Apple 和 Google 允许深度链接打开您的应用,必须在您的网站和应用之间建立双向关联。必须为每个平台创建一个文件,并放置在您网站的 .well-known 文件夹中,如下所示:https://beerswift.app/.well-known/。

继续查看 iOS 和 Android 配置详情。

iOS 配置

iOS 配置包括创建网站关联文件和配置原生应用以识别应用域名。

您必须注册 Apple Developer Program。

创建网站关联文件

首先,登录 Apple Developer 网站。导航到 "Certificates, Identifiers, & Profiles" 部分,选择您的应用标识符。记下 Team ID 和 Bundle ID,然后在 Capabilities 下,切换 "Associated Domains" 然后保存:

iOS Identifier Config

接下来,创建网站关联文件(apple-app-site-association)。

注意:尽管它是 JSON 文件,但不要使用文件扩展名保存。

以下是 apple-app-site-association 文件的示例。请务必将 TEAMID.BUNDLEID 替换为您自己的 ID(例如:8L65AZE66A.com.netkosoft.beerswift)。

{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMID.BUNDLEID",
"paths": ["*"]
}
]
}
}

接下来,将文件上传到您的网站(托管在 HTTPS 上),然后使用 Apple 的工具 在此处 验证其配置是否正确。URL 应遵循此格式:https://beerswift.app/.well-known/apple-app-site-association

添加关联域名

最后一步是配置 iOS 应用以识别传入链接。打开 Xcode,然后导航到 Signing & Capabilities。点击 "+ Capability",然后选择 Associated Domains。在出现的 Domains 条目中,使用格式 applinks:yourdomain.com 进行编辑:

Xcode Associated Domain

Android 配置

Android 配置包括创建网站关联文件和配置原生应用以使用 intent filter 识别应用链接。

创建网站关联文件

网站关联文件需要您的 Android 证书的 SHA256 指纹。

如果您已在 Google Play Store 中启用自动签名,您可以通过访问 https://play.google.com/console,选择您的应用,然后选择 Setup、App Signing,并复制您的 SHA256 应用签名证书指纹。

如果您尚未签署您的应用或启用自动签名,并且还没有证书,您可以创建一个新证书:

keytool -genkey -v -keystore KEY-NAME.keystore -alias ALIAS -keyalg RSA -keysize 2048 -validity 10000

使用您现有的(或新创建的)Keystore 证书,使用 keytool 命令列出密钥库的详细信息:

keytool -list -v -keystore my-release-key.keystore

打印输出将包含 SHA256 指纹:

Keytool output

接下来,使用 Google 的 Asset Links 工具 创建网站关联文件。填写网站域名、应用包名和 SHA256 指纹,然后点击 "Generate statement":

Android Identifier Config

将 JSON 输出复制到 .well-known/assetlinks.json 下的新本地文件中。

// assetlinks.json
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.netkosoft.beerswift",
"sha256_cert_fingerprints": ["43:12:D4:27:D7:C4:14..."]
}
}
]

将文件部署到您的网站(托管在 HTTPS 上),然后通过点击 Asset Link 工具中的 "Test statement" 按钮进行验证。如果配置正确,将显示一条成功消息:

成功!主机 [website] 授予应用深度链接到 [app package]。

添加 Intent Filter

最后一步是配置 Android 应用以识别传入链接。为此,请在 AndroidManifest.xml<activity> 元素内 添加一个新的 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:scheme="https" android:host="beerswift.app" />
</intent-filter>

完整的 Activity 应该类似于这样:

<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
android:name="com.netkosoft.beerswift.MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</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:scheme="https" android:host="beerswift.app" />
</intent-filter>
</activity>

详情:网站配置

网站配置将根据所使用的工具和后端而有所不同。以下是一些建议。

Angular

将关联文件放在 src/.well-known 下。接下来,配置构建过程以保持这些文件原样部署(确保 Apple/Google 可以正确读取它们)。打开 angular.json,在 architect => assets 下,向数组添加一个新条目:

{
"glob": "**/*",
"input": "src/.well-known",
"output": ".well-known/"
}

构建然后部署网站。

NuxtJS

将关联文件放在 static/.well-known 下。无需额外步骤;只需构建然后部署网站。

React

将关联文件放在 public/.well-known 下。无需额外步骤;只需构建然后部署网站。

WordPress

有关 WordPress 的说明,请参见 此处

验证

要验证网站和原生应用是否正确配置,网站需要托管网站关联文件,但应用不需要在应用商店中。

将设备连接到您的计算机,构建并部署原生应用,然后通过点击网站链接进行测试。如果原生应用打开,则所有步骤都已正确实施。

资源