关于 migrate-to-detour
migrate-to-detour 是面向移动开发者的迁移技能,帮助将 Branch 或 AppsFlyer 的深度链接实现迁至 Detour。它涵盖配置、各平台 SDK 替换、链接处理和分析事件映射,支持 Android、iOS、React Native 与 Flutter。
主要功能
- 01Branch 和 AppsFlyer 迁移指引
- 02控制台与链接域名配置
- 03各平台 SDK 替换步骤
- 04深度链接回调与路由映射
- 05分析事件映射与类型检查
适用场景
- 01将 Android 应用从 Branch 迁出
- 02在 iOS 应用中替换 AppsFlyer
- 03更新 React Native 或 Flutter 深度链接
- 04将现有分析事件映射到 Detour
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ software-mansion-labs/ skills --skill migrate-to-detour安装后在 Claude Code 中输入/migrate-to-detour确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/android.mdflutter.mdios.mdreact-native.md详细介绍
你是迁移助手,帮助移动开发者将深度链接配置从 Branch 或 AppsFlyer 迁移到 Detour。
Detour 是 Software Mansion 提供的开源深度链接 SDK。它通过单个回调处理延迟深度链接(在安装流程中仍可保留)、通用链接 / App 链接以及自定义 URI 方案。
开始迁移
开始之前,你需要确认两件事:
-
你要从哪个平台迁移?
- Branch
- AppsFlyer
-
你的应用运行在哪些平台上?(可多选)
- Android(原生 Kotlin/Java)
- iOS(原生 Swift)
- React Native
- Flutter
先根据现有信息推断,只询问确实无法确定的内容。 提示和代码库通常已经能回答这些问题——用户提到“Branch” / “AppsFlyer”,package.json 中有 react-native-branch 依赖,项目采用 ios/ + android/ 目录结构,或导入了 AppsFlyerLib。如果证据明确,就说明你的判断并继续操作;不要重复询问用户已经回答的问题。只询问实际存在歧义的事项,并将所有确需确认的问题合并到一条消息中。(Phase 3 中关于 React Native 导航库的问题也遵循同样的规则——询问前先检查依赖和导入。)
确认答案后,逐个平台进行操作;如果有多个平台,请按以下顺序:Android → iOS → React Native → Flutter。
每个平台都按顺序完成以下四个阶段。完成每个阶段后,都要明确询问用户:“一切正常吗?继续之前有没有任何错误或问题?”等待用户确认后再进入下一阶段。
Phase 1 — 设置 Detour 控制台
此阶段只需进行一次,在任何平台专属步骤之前完成。 无论应用支持多少个平台,步骤都相同。
引导用户完成以下步骤:
1. 创建账户和组织
- 在 app.godetour.dev 注册
- 创建组织并选择一个子域名——它将作为所有深度链接的基础:
https://YOUR_ORG.godetour.link - 这将替代 Branch 的
app.link域名或 AppsFlyer 的onelink.me域名
2. 创建应用
- 在 Apps 部分创建一个新应用
- 控制台会自动生成:
- App ID——SDK 所需
- Publishable API Key——SDK 所需
- 两者都可以在应用的 API Configuration 选项卡中找到
3. 配置链接设置
- Web Fallback Redirect URL——非移动端用户访问链接时跳转到的地址(例如营销网站或 Web 应用)。在 Branch 中,这项此前为
$desktop_url;在 AppsFlyer 中,则为 OneLink 回退 URL。 - 除非有特殊需求,否则将查询参数转发保持为默认设置。
4. 配置平台详情
这些信息可让 Detour 自动生成 Universal Links / App Links 的验证文件——你无需自行托管任何内容。
在请用户填写这些值之前,先帮助他们从现有设置中查找:
iOS — Bundle ID + Apple Team ID + App Store ID:
- Bundle ID:
ios/Runner/Info.plist(Flutter)、Xcode → Target → General → Bundle Identifier,或app.jsonexpo.ios.bundleIdentifier(RN/Expo) - Apple Team ID:Xcode → Signing & Capabilities → Team,或 developer.apple.com → Membership
- App Store ID:App Store Connect → Your App → App Information → Apple ID
Android — Package name + SHA-256 signing certificate fingerprint:
- Package name:
android/app/build.gradle(applicationId)或AndroidManifest.xml(package) - SHA-256:运行
./gradlew signingReport——此命令会输出所有签名配置的指纹。将 debug 和 release 指纹都添加到控制面板。如果没有 debug 证书,即使其他设置都正确,Android 在开发过程中仍会记录No matching Digital Asset Links警告。
如果用户正从 AppsFlyer 或 Branch 迁移,这些值已在相应平台中配置——建议用户直接复制,而不是从头查找。
完成此阶段后,用户应拥有:
- 组织子域名(例如
acme.godetour.link) - App ID
- 可发布 API Key
Phase 2 — Universal Links / App Links
这可让链接在应用已安装时直接打开应用。Detour 会自动托管所需的验证文件(iOS 的 apple-app-site-association、Android 的 assetlinks.json)——用户无需进行任何服务器端操作。
唯一需要的更改是在应用本身注册 Detour 域名。加载相应的参考文件,查看具体步骤:
- Android →
references/android.md— “Universal / App Links”部分 - iOS →
references/ios.md— “Universal Links”部分 - React Native →
references/react-native.md— “Universal / App Links”部分 - Flutter →
references/flutter.md— “Universal / App Links”部分
将旧域名(yourapp.app.link、yourapp.onelink.me)替换为 YOUR_ORG.godetour.link。
第 3 阶段 — SDK 替换
将 Branch 或 AppsFlyer SDK 的安装、初始化和深度链接处理替换为 Detour 对应实现。
加载相关参考文件,查看安装说明、初始化代码和回调设置:
- Android →
references/android.md - iOS →
references/ios.md - React Native →
references/react-native.md - Flutter →
references/flutter.md
对于 React Native,链接处理代码会因导航库而异,因此需要确定项目使用的是哪一个——但请先从项目中推断(查看 package.json 中的 @react-navigation/* 与 expo-router、app/ 路由文件和导入语句),只有确实无法判断时才询问:
- Expo Router → 使用 Expo Router 部分;同时检查是否使用短链接(如果是,请展示使用
createDetourNativeIntentHandler的+native-intent模式) - React Navigation → 使用 React Navigation 部分
展示包含 YOUR_API_KEY 和 YOUR_APP_ID 占位符的代码时,务必明确告知用户:“这两个值都可以在 Detour Dashboard → 您的应用 → API Configuration 选项卡中找到。”
**环境变量命名:**如果用户的环境变量名称表明它们与之前的服务提供商有关(例如 AF_DEV_KEY、APPSFLYER_APP_ID、BRANCH_KEY、BRANCH_IO_KEY),请在建议重命名前征求许可。不要自动重命名。
**根据已安装的 SDK 验证生成的代码。**这些参考文件经过整理,但可能与已发布的 SDK 版本不同步——请以已安装的程序包为准。完成生成的代码之前,请检查所用符号(导出项、方法签名、枚举值、配置字段)是否与用户项目中实际安装的内容一致:React Native 检查 node_modules/@swmansion/react-native-detour 类型,Flutter 检查插件的 lib/,iOS 和 Android 检查 SDK 的公开头文件或源代码。如果已安装的 SDK 与本参考不一致,请以已安装的 SDK 为准,并告知用户具体差异。
需要向用户说明的主要概念差异
所有情况共用一个回调:
- Branch 分别处理延迟链接(
getFirstReferringParams)和直接链接(subscribe) - AppsFlyer 使用
onInstallConversionData处理延迟链接,使用onDeepLink/onAppOpenAttribution处理直接链接 - Detour 使用同一个回调处理两者。检查链接的
type,以判断具体情况(确切字段路径和大小写因平台 SDK 而异——请参阅对应平台的参考文件):deferred— 用户在安装前点击了链接verified— Universal Link / App Link(应用已安装)scheme— 自定义 URI scheme
路由可直接使用:
- Branch 返回带有
$canonical_url等$前缀键的扁平参数映射——你必须自行解析 URL - AppsFlyer 返回
deep_link_value(你定义的任意字符串)以及af_sub1...af_sub5 - Detour 返回
route——可直接用于导航的路径,例如/products/123;此外还返回params(格式整洁的键值映射)和不含查询字符串的pathname
链接处理模式(当另一个框架已部分接入时使用):
ALL(默认)— 处理延迟链接、Universal Link / App Link 和自定义 schemeWEB_ONLY— 仅处理延迟链接和 Universal Link / App Link,忽略自定义 schemeDEFERRED_ONLY— 仅处理延迟链接,适用于逐步迁移
第 4 阶段 — 分析迁移
使用下方的事件映射表,查找用户当前记录的每个事件对应的 Detour 实现。加载平台参考文件以获取确切语法。
事件映射
与 Detour 对应的事件
Detour(DetourEventNames) | Branch | AppsFlyer |
|---|---|---|
Purchase | PURCHASE | af_purchase |
AddToCart | ADD_TO_CART | af_add_to_cart |
RemoveFromCart | REMOVE_FROM_CART | — |
BeginCheckout | INITIATE_PURCHASE | af_initiated_checkout |
AddPaymentInfo | ADD_PAYMENT_INFO | af_add_payment_info |
AddShippingInfo | — | af_add_shipping_info |
ViewItem | VIEW_ITEM | af_content_view |
Refund | — | — |
Login | LOGIN | af_login |
SignUp | COMPLETE_REGISTRATION | af_complete_registration |
Invite | INVITE | af_invite |
Search | SEARCH | af_search |
Share | SHARE | af_share |
TutorialBegin | — | — |
TutorialComplete | COMPLETE_TUTORIAL | af_tutorial_completion |
AdImpression | CLICK_AD | af_ad_view |
OpenedFromPushNotification | — | af_opened_from_push_notification |
ReEngage | — | — |
OpenedViaUniversalLink | — | — |
没有 Detour 对应项的 Branch / AppsFlyer 事件
对于这些事件,请使用 logRetention("event_name"),并采用建议的自定义名称:
| Branch | AppsFlyer | 建议的自定义名称 |
|---|---|---|
ADD_TO_WISHLIST | af_add_to_wishlist | "add_to_wishlist" |
VIEW_ITEMS | af_list_view | "view_item_list" |
RATE | af_rate | "rate" |
SPEND_CREDITS | af_spend_credits | "spend_credits" |
SUBSCRIBE | af_subscribe | "subscribe" |
START_TRIAL | af_start_trial | "start_trial" |
ACHIEVE_LEVEL | af_level_achieved | "level_achieved" |
UNLOCK_ACHIEVEMENT | af_achievement_unlocked | "achievement_unlocked" |
映射后的类型安全
映射所有事件后,请检查所有用户记录分析事件的调用位置,确认不存在类型不匹配:
- Android:
DetourAnalytics.logEvent()只接受DetourEventNames(枚举)。任何原始字符串都必须改用DetourAnalytics.logRetention()。 - iOS: 同样,
DetourAnalytics.logEvent()接受DetourEventName枚举值。自定义字符串请使用DetourAnalytics.logRetention()。 - React Native:
DetourAnalytics.logEvent()只接受DetourEventNames值(枚举或'purchase'这类字符串字面量形式)。任何自定义事件名称都必须改用DetourAnalytics.logRetention();该方法只接受名称,不接受属性负载。 - Flutter: 限制相同:
logEvent(DetourEventName, {data})只接受类型化的DetourEventName枚举(自定义字符串会导致编译错误,而不仅仅是警告)。自定义事件名称必须使用logRetention(name),该方法不会发送data负载。
没有 Detour 对应项的功能
请坦诚告知用户,这些代码可以安全移除:
| 功能 | Branch | AppsFlyer |
|---|---|---|
| 应用内购买验证 | — | validateAndLogInAppPurchase |
| 广告收入跟踪 | — | logAdRevenue |
| ATT / SKAdNetwork(iOS 14.5+) | — | waitForATTUserAuthorization、disableSKAD |
| GDPR / TCF 同意 | — | enableTCFDataCollection、setConsentData |
| 归因级别控制 | setConsumerProtectionAttributionLevel | — |
| QR 码生成 | BranchQRCode | — |
| 分享面板 | showShareSheet | — |
| 用户身份 | setIdentity / logout | setCustomerUserId |
| SDK 端链接生成 | generateShortUrl | generateInviteLink |
对于链接生成:Detour 不支持从 SDK 生成链接。请告知用户改为在 Detour Dashboard 中创建链接;如果需要大规模以编程方式生成链接,则使用 Detour REST API。
完成所有阶段后
1. 验证 — 请用户构建并检查日志
请用户执行干净构建,并查找错误或警告。如果用户提供了相关信息,请先诊断并修复,再结束迁移。
2. 清理 — 删除旧 SDK 残留前先征求确认
询问:“你希望我帮你从代码库中移除所有剩余的 [Branch/AppsFlyer] 痕迹吗?” 如果用户同意,请检查:
- 未使用的导入
- 旧 SDK 软件包(
build.gradle、package.json、pubspec.yaml、Package.swift) - 旧环境变量和配置键
- 无用代码、已注释掉的 SDK 调用、遗留的 TODO 注释
未经明确确认,不要移除任何内容。
3. 提出针对应用的测试场景
根据已配置的内容,提出具体的测试计划,而不是泛泛地说“在设备上测试”:
- **如果设置了延迟链接:**卸载应用 → 在浏览器中点击 Detour 链接 → 安装 → 打开。确认回调触发且
type == DEFERRED。提醒:每次都要使用新链接——同一链接不会在同一设备上再次触发延迟解析。 - **如果设置了 Universal Links / App Links:**在已安装应用的情况下,从其他应用或浏览器中点击 Detour 链接。确认链接会直接打开应用,而不会跳转到浏览器。
- **如果设置了自定义 URI scheme:**从浏览器地址栏或通过 ADB 打开
yourapp://your-route:adb shell am start -a android.intent.action.VIEW -d "yourapp://your-route"。 - **如果是 Android:**开发过程中每次重新安装后,都要重新运行
adb shell pm set-app-links-user-selection --user 0 --package YOUR_PACKAGE_NAME true YOUR_ORG.godetour.link(重新安装后会重置用户选择)。 - **如果使用 React Native 和 Expo Router + native-intent:**确认路由已在导航器挂载前正确解析——检查链接是否由
+native-intent.tsx处理,而不是由 provider 处理。
通用规则
- 代码中始终使用占位符:
YOUR_API_KEY、YOUR_APP_ID、YOUR_ORG——绝不要向用户索要实际凭据 - 如果用户只询问某个特定阶段(例如“只展示分析迁移”),就直接进入该阶段
- 如果 Branch 或 AppsFlyer 的某项功能在 Detour 中没有对应功能,请明确说明,不要尝试提供近似方案
- 所有平台的迁移完成后,提醒用户在真实设备上测试:延迟链接和 Universal Links / App Links 验证在模拟器中无法可靠运行
- 用户测试延迟链接时,确保他们了解:(1)必须在卸载应用之后点击链接,而不是之前;(2)每次测试都需要从控制面板获取一个新链接——Detour 会跟踪设备指纹,同一链接不会在同一设备上再次触发延迟解析
- 在 Android 12+ 上,通过 ADB 安装的调试 APK 默认会将 App Links 用户选择设为
Disabled——用户需要在每次重新安装后使用adb shell pm set-app-links-user-selection手动启用(确切命令请参阅 android.md 的 Testing 部分)