Apple Handoff
编辑页面
了解如何使用 Expo Router 和 Apple Handoff 在 Apple 设备之间无缝继续应用导航。
For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.
Apple Handoff 是一项功能,它使用户能够在另一台设备上继续浏览您的应用或网站。Expo Router 为此功能自动处理所有运行时路由。不过,一次性配置必须手动设置。
在 Expo Router 中,底层的 iOS API(NSUserActivity)需要一个 webpageUrl,操作系统建议将其作为切换到您的应用时的当前 URL。expo-router/head 组件有一个可选的原生模块,可以自动将 webpageUrl 设置为 Expo Router 中当前聚焦的路由。
设置
以下限制和注意事项很重要:
- Handoff 仅适用于 Apple。
- Handoff 不能在 Expo Go 应用中使用,因为它需要构建时配置。
- Handoff 需要配置 universal links,至少在 iOS 上,并且包含
activitycontinuation对象。 - Handoff 需要在您希望支持的每个页面上使用
expo-router/head组件;如果您希望所有页面都可连续接续,则可以在根布局中使用。
为确保 public/.well-known/apple-app-site-association 文件配置正确,它必须包含 activitycontinuation 键,并带有一个 apps 数组,其中包含您的应用的 bundle ID 和 Team ID,格式为 <APPLE_TEAM_ID>.<IOS_BUNDLE_ID>。例如,QQ57RJ5UTD.app.expo.acme,其中 QQ57RJ5UTD 是 Team ID,app.expo.acme 是 bundle 标识符。
{ "applinks": { "details": [ { "appIDs": ["<APPLE_TEAM_ID>.<IOS_BUNDLE_ID>"], "components": [ { "/": "*", "comment": "匹配所有路由" } ] } ] }, "activitycontinuation": { "apps": ["<APPLE_TEAM_ID>.<IOS_BUNDLE_ID>"] }, "webcredentials": { "apps": ["<APPLE_TEAM_ID>.<IOS_BUNDLE_ID>"] } }
webcredentials对象是可选的,但建议添加。
您可以使用以下命令,根据您的 app config 生成 apple-app-site-association 文件:
- npx setup-safari请参阅 测试深度链接 指南,以在开发环境中测试 handoff。
Expo Head 设置
请确保在 app.config.tsx 文件中使用 expo-router 配置插件设置 Handoff origin。此 URL 将在用户切换到您的应用时用作 webpageUrl。
// 请务必将其更改为对您的项目唯一的值。 process.env.EXPO_TUNNEL_SUBDOMAIN = 'bacon-router-sandbox'; const ngrokUrl = `${process.env.EXPO_TUNNEL_SUBDOMAIN}.ngrok.io`; /** @type {import('expo/config').ExpoConfig} */ module.exports = { // ... ios: { associatedDomains: [ `applinks:${ngrokUrl}`, `activitycontinuation:${ngrokUrl}`, `webcredentials:${ngrokUrl}`, // 在此处添加额外的生产 URL。 // `applinks:example.com`, // `activitycontinuation:example.com`, // `webcredentials:example.com`, ], }, plugins: [ [ 'expo-router', { // 注意:在 "headOrigin" 中,URL 必须以 "https://" 开头 headOrigin: process.env.NODE_ENV === 'development' ? `https://${ngrokUrl}` : 'https://my-website-example.com', }, ], ], };
在测试 handoff 到原生端时,不要使用仅限开发环境的
?mode=developer后缀。
配置完应用配置后,请使用以下命令重新生成您的原生项目:
- npx expo prebuild -p ios在开发过程中,您必须在将应用安装到设备之前先启动网站。这是因为当您安装应用时,操作系统会触发 Apple 的服务器去 ping 您的网站,以获取 .well-known/apple-app-site-association 文件。如果网站未运行,操作系统将无法找到该文件,handoff 也将无法工作。如果发生这种情况,请使用 npx expo run:ios -d 重新构建原生应用。
用法
在任何您想支持 handoff 的路由中,使用来自 expo-router/head 的 Head 组件:
import Head from 'expo-router/head'; import { Text } from 'react-native'; export default function App() { return ( <> <Head> <meta property="expo:handoff" content="true" /> </Head> <Text>你好,世界</Text> </> ); }
Meta 标签
expo-router/head 组件支持以下 meta 标签:
| Meta 标签 | 描述 |
|---|---|
expo:handoff | 设置为 true 以为当前路由启用 handoff。默认值为 false。(仅 iOS) |
og:title 和 <title> | 为 NSUserActivity 设置标题;在 handoff 中不使用此项。 |
og:description | 为 NSUserActivity 设置描述;在 handoff 中不使用此项。 |
og:url | 设置用户切换到您的应用时应打开的 URL。默认使用应用内当前 URL,并以 expo-router 配置插件中的 headOrigin 属性作为 baseURL。传入相对路径时,会将 headOrigin 追加到该路径前。 |
如果您想在不同平台之间切换这些值,可以使用 Platform.select:
import Head from 'expo-router/head'; export default function App() { return ( <Head> <meta property="og:url" content={Platform.select({ web: 'https://expo.dev', default: null })} /> </Head> ); }
调试
确保你的 Apple 设备已启用接力。你可以按照下面的步骤进行测试,但将你的应用替换为 Safari。
- 在你的设备上打开原生应用。
- 导航到应用中支持接力的路由,该路由正在渲染 Expo Router 的
<Head />元素。 - 切换到你的 Mac,并点击 Dock 中该应用的接力图标。
- 切换到你的 iPhone 或 iPad,打开 App 切换器,然后点击屏幕底部的应用横幅。
如果你在 iPhone 的 App 切换器中只看到了 Safari 图标,那么说明接力未正常工作。
故障排查
你可以使用验证器(例如 AASA Validator)来测试 Apple App Site Association 文件(public/.well-known/apple-app-site-association)。
如果你遇到问题,最好的做法是在应用中启用最激进的接力设置。这可以确保任何可能的路由都可链接。你可以通过确保 public/.well-known/apple-app-site-association 文件匹配所有路由来实现:
{ "applinks": { "details": [ { "appIDs": ["<APPLE_TEAM_ID>.<IOS_BUNDLE_ID>"], "components": [ { "/": "*", "comment": "匹配所有路由" } ] } ] } }
在应用中,确保你没有条件性地渲染 <Head /> 元素(例如在 if/else 块中),它必须在你想要支持接力的每个页面上都被渲染。我们建议将其添加到 根布局 组件中,以确保在调试时每条路由都可链接。
在设备上安装应用之前,确保你可以访问 Ngrok URL(例如通过浏览器访问)。如果你无法访问该 URL,操作系统将无法找到文件,接力也将无法工作。
当配置了关联域时,npx expo run:ios 和 Xcode 都会对你的应用进行代码签名,这是接力和通用链接正常工作的必要条件。
Expo Go 应用不支持 Mac 与 iPhone/iPad 之间的接力。你必须在设备上构建并安装你的应用。
如果你在 iPhone 的 App 切换器中看到了 Safari 图标,那么这意味着接力未正常工作。
- 测试到原生端的接力时,确保你没有使用
?mode=developer后缀。 - 另外,确保你没有使用本地开发服务器 URL。例如,
http://localhost:8081不能作为有效的 app site association 链接使用;请在浏览器中打开正在运行的 Ngrok URL 进行测试。 - 确保你的 public/.well-known/apple-app-site-association 文件包含
activitycontinuation字段。 - 我们观察到,在 iOS 16.3.1 和 macOS 13.0(Ventura)中,以
app.和io.开头的 bundle identifier 有时不会触发原生应用在 iOS 任务切换器中显示。请使用com.作为 bundle identifier 的第一部分。
你的 public/.well-known/apple-app-site-association 必须通过安全 URL(HTTPS)提供。如果你使用开发隧道,你必须使用 EXPO_TUNNEL_SUBDOMAIN 环境变量来配置开发隧道的子域名。开发环境下测试需要使用隧道,因为你需要 SSL 才能使用通用链接;Expo CLI 通过运行 npx expo start --tunnel 提供了内置支持。
检查你的 ios/project/project.entitlements 文件中 com.apple.developer.associated-domains 键下的内容。这应当包含与你的网站服务器/网站相同的域名。URL 不能包含协议(https://)或额外的路径名、查询参数或片段。
仍然卡住
这是一个很重要但也非常难配置的功能。Expo Router 自动化了许多相关环节,Expo CLI 自动化了大部分配置和托管。不过,硬件设置仍然可能被配置错误。
如果一切都失败了,你可以尝试按照 Apple 文档 中的步骤来调试该问题。请注意:
- “将用户活动表示为
NSUserActivity的实例。” 由 Expo Head 原生模块执行。 - “当用户在应用中执行操作时更新活动实例。” 由挂载/渲染内部包含元标签
<meta property="expo:handoff" content="true" />的<Head />组件来执行。 - “在你的应用中的其他设备上接收来自接力的活动。” 由 Expo Head 原生模块中的 App Delegate 订阅者 执行。它用于在你接力到原生应用时将你重定向到正确的路由。
已知问题
从网页到原生的接力不支持客户端路由。这意味着 App 切换器中显示的 URL 将是你点击链接或重新加载页面时所在页面的 URL。这是 Web 平台的限制,Expo Router 无法修复。