深度链接
本指南将介绍如何在不同平台上配置您的应用程序以处理深度链接。要处理传入链接,您需要处理两种情况
- 如果应用程序之前未打开,则深度链接需要设置初始状态
- 如果应用程序已打开,则深度链接需要更新状态以反映传入链接
React Native 提供了一个 Linking
来接收传入的链接通知。React Navigation 可以与 Linking
模块集成,以自动处理深层链接。在 Web 上,React Navigation 可以与浏览器的 history
API 集成,以处理客户端的 URL。请参阅 配置链接 以了解有关如何在 React Navigation 中配置链接的更多详细信息。
虽然您不需要使用 React Navigation 的 linking
属性,并且可以通过使用 Linking
API 并从那里导航来自己处理深层链接,但这将比使用 linking
属性(为您处理许多边缘情况)复杂得多。因此,我们不建议您自己实现它。
下面,我们将介绍必要的配置,以使深层链接集成正常工作。
使用 Expo 项目进行设置
首先,您需要为您的应用程序指定一个 URL 方案。这对应于 URL 中 ://
之前的字符串,因此如果您的方案是 mychat
,则指向您的应用程序的链接将是 mychat://
。您可以在 app.json
中注册一个方案,方法是在 scheme 键下添加一个字符串
{
"expo": {
"scheme": "mychat"
}
}
接下来,安装 expo-linking
,我们需要它来获取深层链接前缀
npx expo install expo-linking
然后,让我们配置 React Navigation 以使用 scheme
来解析传入的深层链接
import * as Linking from 'expo-linking';
const prefix = Linking.createURL('/');
function App() {
const linking = {
prefixes: [prefix],
};
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
{/* content */}
</NavigationContainer>
);
}
之所以需要使用 Linking.createURL
,是因为方案将根据您是在客户端应用程序中还是在独立应用程序中而有所不同。
在 app.json
中指定的方案仅适用于独立应用程序。在 Expo 客户端应用程序中,您可以使用 exp://ADDRESS:PORT/--/
进行深层链接,其中 ADDRESS
通常是 127.0.0.1
,而 PORT
通常是 19000
- 当您运行 expo start
时会打印出 URL。Linking.createURL
函数将其抽象出来,因此您无需手动指定它们。
如果您使用的是通用链接,则还需要将您的域添加到前缀中
const linking = {
prefixes: [Linking.createURL('/'), 'https://app.example.com'],
};
使用原生 React Native 项目进行设置
在 iOS 上设置
让我们配置原生 iOS 应用,使其根据 mychat://
URI 方案打开。
您需要通过以下步骤将 RCTLinking
链接到您的项目。为了能够监听传入的应用链接,您需要在项目的 AppDelegate.m
中添加以下行
// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>
// Add this inside `@implementation AppDelegate` above `@end`:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
如果您的应用使用的是 通用链接,您还需要添加以下代码
// Add this inside `@implementation AppDelegate` above `@end`:
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
现在您需要将方案添加到您的项目配置中。
最简单的方法是使用 uri-scheme
包,运行以下命令
npx uri-scheme add mychat --ios
如果您想手动操作,请在 Xcode 中打开项目(例如 SimpleApp/ios/SimpleApp.xcworkspace
)。在侧边栏中选择项目,然后导航到信息选项卡。向下滚动到“URL 类型”并添加一个。在新的 URL 类型中,将标识符和 URL 方案设置为您想要的 URL 方案。
为了确保通用链接在您的应用中正常工作,您还需要在您的服务器上设置 关联域。
混合 React Native 和原生 iOS 应用
如果您在混合应用中使用 React Navigation - 一个包含 Swift/ObjC 和 React Native 部分的 iOS 应用 - 您可能在 Podfile
中缺少 RCTLinkingIOS
子规范,该规范默认安装在新的 React Native 项目中。要添加此规范,请确保您的 Podfile
如下所示
pod 'React', :path => '../node_modules/react-native', :subspecs => [
. . . // other subspecs
'RCTLinkingIOS',
. . .
]
在 Android 上设置
要配置 Android 中的外部链接,您可以在清单中创建一个新的意图。
最简单的方法是使用 uri-scheme
包:npx uri-scheme add mychat --android
。
如果你想手动添加,打开 SimpleApp/android/app/src/main/AndroidManifest.xml
,并进行以下调整
- 将
MainActivity
的launchMode
设置为singleTask
,以便在现有MainActivity
上接收意图(这是默认设置,因此你可能不需要实际更改任何内容)。 - 在
MainActivity
条目中添加新的intent-filter
,并使用VIEW
类型操作
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mychat" />
</intent-filter>
</activity>
类似于 iOS 上的通用链接,你也可以使用域来将应用程序与 Android 上的网站关联,方法是 验证 Android 应用程序链接。首先,你需要配置你的 AndroidManifest.xml
- 在你的
<intent-filter>
条目中添加android:autoVerify="true"
。 - 在
<intent-filter>
中的新<data>
条目中添加你的域的scheme
和host
。
添加它们后,它应该看起来像这样
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mychat" />
</intent-filter>
<intent-filter>
<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>
</activity>
然后,你需要 声明网站和意图过滤器之间的关联,方法是托管一个数字资产链接 JSON 文件。
测试深度链接
在测试深度链接之前,请确保你已在模拟器/模拟器/设备中重建并安装应用程序。
如果你在 iOS 上测试,请运行
npx react-native run-ios
如果你在 Android 上测试,请运行
npx react-native run-android
如果你使用的是 Expo 管理的工作流程并在 Expo 客户端上测试,则无需重建应用程序。但是,你需要使用运行 expo start
时打印的正确地址和端口(见上文),例如 exp://127.0.0.1:19000/--/
。
如果你想在 Expo 应用程序中使用自定义方案进行测试,你需要通过运行 expo build:ios -t simulator
或 expo build:android
来重建你的独立应用程序,并安装生成的二进制文件。
使用 npx uri-scheme
测试
uri-scheme
包是一个命令行工具,可用于测试 iOS 和 Android 上的深层链接。它可以按如下方式使用
npx uri-scheme open [your deep link] --[ios|android]
例如
npx uri-scheme open "mychat://chat/jane" --ios
或者如果使用 Expo 客户端
npx uri-scheme open "exp://127.0.0.1:19000/--/chat/jane" --ios
在 iOS 上使用 xcrun
测试
xcrun
命令可以按如下方式使用,以使用 iOS 模拟器测试深层链接
xcrun simctl openurl booted [your deep link]
例如
xcrun simctl openurl booted "mychat://chat/jane"
在 Android 上使用 adb
测试
adb
命令可以按如下方式使用,以使用 Android 模拟器或连接的设备测试深层链接
adb shell am start -W -a android.intent.action.VIEW -d [your deep link] [your android package name]
例如
adb shell am start -W -a android.intent.action.VIEW -d "mychat://chat/jane" com.simpleapp
或者如果使用 Expo 客户端
adb shell am start -W -a android.intent.action.VIEW -d "exp://127.0.0.1:19000/--/chat/jane" host.exp.exponent
第三方集成
React Native 的 Linking
不是处理深层链接的唯一方法。您可能还想集成其他服务,例如 Firebase 动态链接、Branch 等,它们提供自己的 API 来接收传入链接的通知。
要实现此目的,您需要覆盖 React Navigation 如何订阅传入链接。为此,您可以提供自己的 getInitialURL
和 subscribe
函数
const linking = {
prefixes: ['myapp://', 'https://myapp.com'],
// Custom function to get the URL which was used to open the app
async getInitialURL() {
// First, you would need to get the initial URL from your third-party integration
// The exact usage depend on the third-party SDK you use
// For example, to get the initial URL for Firebase Dynamic Links:
const { isAvailable } = utils().playServicesAvailability;
if (isAvailable) {
const initialLink = await dynamicLinks().getInitialLink();
if (initialLink) {
return initialLink.url;
}
}
// As a fallback, you may want to do the default deep link handling
const url = await Linking.getInitialURL();
return url;
},
// Custom function to subscribe to incoming links
subscribe(listener) {
// Listen to incoming links from Firebase Dynamic Links
const unsubscribeFirebase = dynamicLinks().onLink(({ url }) => {
listener(url);
});
// Listen to incoming links from deep linking
const linkingSubscription = Linking.addEventListener('url', ({ url }) => {
listener(url);
});
return () => {
// Clean up the event listeners
unsubscribeFirebase();
linkingSubscription.remove();
};
},
config: {
// Deep link configuration
},
};
与上面的示例类似,您可以集成任何提供获取初始 URL 和使用 getInitialURL
和 subscribe
选项订阅新传入 URL 的方法的 API。