mcpField
C
capacitor-deep-linking

capacitor-deep-linking

github.com/cap-go开发731.3k 次安装2 周前更新
代码仓库

关于 capacitor-deep-linking

为 Capacitor 开发者提供深度链接配置与排查指导,涵盖自定义 scheme、iOS Universal Links 和 Android App Links,并处理冷启动与热启动路由差异。

主要功能

  1. 01配置自定义 scheme 与已验证链接
  2. 02处理冷启动和热启动 URL
  3. 03适配 iOS SceneDelegate 生命周期
  4. 04校验链接并验证平台配置
  5. 05排查 OAuth 等回跳问题

适用场景

  1. 01将 OAuth 或支付回调路由回应用
  2. 02修复链接启动应用后落到首页的问题
  3. 03诊断 Android 域名验证失败
  4. 04适配 Capacitor 8.5+ 深度链接变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-deep-linking

安装后在 Claude Code 中输入/capacitor-deep-linking确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.json
references/
android-app-links.md
ios-scene-delegate.md
ios-universal-links.md
routing-patterns.md

详细介绍

Capacitor 中的深层链接

将自定义协议链接、iOS 通用链接和 Android 应用链接路由到 Web 应用。

适用场景

满足以下情况时触发:

  • 为 Capacitor 应用添加 myapp:// 协议、通用链接或应用链接
  • 链接打开的是浏览器而非应用,或打开了应用但停留在首页
  • 温启动时触发了 appUrlOpen,但冷启动时缺少 URL(或反之)
  • 更新到 Capacitor 8.5+ / 采用 SceneDelegate.swift 后深层链接失效
  • OAuth / 魔法链接 / 支付重定向必须返回应用
  • adb shell pm get-app-links 显示 none 或 1024,而非 verified

请勿用于:

  • 将整个应用从 AppDelegate 迁移到 SceneDelegate:capacitor-uiscene-migration
  • 通知点击路由:capacitor-push-notifications
  • 调试时捕获原生日志:ios-android-logs
  • Sign in with Apple / Google 插件配置:capacitor-plugins

链接类型

类型平台格式需要托管文件已验证所有权
自定义协议两者myapp://product/123否否(任何应用都可以声明)
通用链接iOShttps://example.com/product/123/.well-known/apple-app-site-association是
应用链接Android 6+https://example.com/product/123/.well-known/assetlinks.json是

对于任何涉及安全的用途(OAuth、魔法链接),优先使用已验证的 https 链接。其他应用可以劫持自定义协议。

工作流

  1. 先检查。 阅读 capacitor.config.*、ios/App/App/Info.plist、ios/App/App/*.entitlements、ios/App/App/AppDelegate.swift、ios/App/App/SceneDelegate.swift(如果存在)、android/app/src/main/AndroidManifest.xml,以及 package.json 中的 @capacitor/app 版本。
  2. 确定 iOS 生命周期路径。
    • Info.plist 中存在 UIApplicationSceneManifest(Capacitor 8.5+ 模板或已迁移的应用)-> URL 事件会到达 SceneDelegate。AppDelegate 中的任何自定义 application(_:open:options:) 或 application(_:continue:restorationHandler:) 代码都是无效代码。参见 references/ios-scene-delegate.md。
    • 没有场景清单 -> 在 8.5 core 上仍可使用 AppDelegate 路径,但 Xcode 27 / Capacitor 9 要求采用场景生命周期。将迁移交由 capacitor-uiscene-migration 处理。
  3. 安装 @capacitor/app(npm install @capacitor/app && npx cap sync)。
  4. 在应用启动时注册一次 JS 处理器(在路由器渲染之前),同时使用 appUrlOpen 和 getLaunchUrl()。参见下文。
  5. 配置平台:自定义协议(Info.plist CFBundleURLTypes、Android <intent-filter>),然后按平台配置已验证链接:
  6. 路由:在框架路由器中配置:references/routing-patterns.md(React、Vue、Angular、OAuth 回调、延迟链接)。
  7. 验证:在真实设备上使用下方的冷启动 / 温启动矩阵。

仅当某个主题适用时,才加载相应参考资料。

JS 处理器(每个应用都需要的部分)

import { App, type URLOpenListenerEvent } from '@capacitor/app';

let lastHandled: string | undefined;

function route(rawUrl: string) {
  if (rawUrl === lastHandled) return; // cold start can deliver the same URL to both paths
  lastHandled = rawUrl;
  const url = new URL(rawUrl);
  // myapp://product/123 -> host "product", pathname "/123"
  // https://example.com/product/123 -> pathname "/product/123"
  const path = url.protocol.startsWith('http')
    ? url.pathname
    : `/${url.host}${url.pathname}`;
  router.navigate(path + url.search); // your router
}

export async function initDeepLinks() {
  await App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => route(event.url));
  const launch = await App.getLaunchUrl(); // resolves undefined or { url }
  if (launch?.url) route(launch.url);
}

注意事项:

  • 自定义协议 URL 解析后,第一个片段位于 host 而非 pathname。请按上述方式规范化两种形式。
  • 在应用启动时注册监听器,而非在延迟加载的页面中注册。事件触发后再添加的监听器无法收到该事件;冷启动时可通过 getLaunchUrl() 补足。
  • 请将监听器中的状态更新封装在框架的 zone / 运行循环中(Angular 使用 NgZone.run),否则导航不会有任何效果。
  • 去重:冷启动时可通过 getLaunchUrl() 和 appUrlOpen 两种方式获取该 URL。
  • 导航前验证路径并设置允许列表;深层链接是不可信输入。

自定义 Scheme 配置

iOS ios/App/App/Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>com.example.app</string>
    <key>CFBundleURLSchemes</key>
    <array><string>myapp</string></array>
  </dict>
</array>

Android AndroidManifest.xml,位于现有的 MainActivity 中(保留模板中的 android:launchMode="singleTask",以便热启动时复用 Activity):

<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="myapp" />
</intent-filter>

验证

在实体设备上运行每一行(通用链接无法在模拟器地址栏中可靠工作;请从 Notes/Messages 中点按链接)。

场景iOSAndroid
自定义 scheme,热启动xcrun simctl openurl booted "myapp://product/123"adb shell am start -W -a android.intent.action.VIEW -d "myapp://product/123" com.example.app
自定义 scheme,冷启动结束应用,然后运行相同的命令adb shell am force-stop com.example.app,然后运行相同的命令
已验证链接,热启动在 Notes 中点按 https://example.com/product/123adb shell am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://example.com/product/123"
已验证链接,冷启动将应用从后台划掉,然后点按链接强制停止应用,然后运行相同的命令
所有权检查curl -sI https://example.com/.well-known/apple-app-site-association(200,且无重定向)adb shell pm get-app-links com.example.app 显示 verified

通过标准:每种情况都会进入正确的路由,appUrlOpen 只记录一次;冷启动时,getLaunchUrl() 会返回该 URL。完成 Capacitor 8.5 场景迁移后,请重新运行完整测试矩阵:冷启动会采用与热启动不同的原生路径(scene(_:willConnectTo:options:),而热启动使用 scene(_:openURLContexts:) / scene(_:continue:))。

迁移后,使用 grep 查找已失效的处理程序:

grep -n "open url: URL\|continue userActivity" ios/App/App/AppDelegate.swift
grep -n "SceneDelegateProxy" ios/App/App/SceneDelegate.swift

错误处理

症状 / 消息原因修复方法
链接在 Safari 中打开,但应用已安装尚未获取 AASA、appID 错误、缺少 entitlement,或用户长按链接并选择了“在 Safari 中打开”通过 Apple CDN 检查 AASA、TEAMID.bundleId 和 applinks: entitlement;长按链接并选择“在 App 中打开”以重置
8.5 更新后,自定义 AppDelegate URL 代码不再运行存在 Scene manifest;iOS 会改为调用 SceneDelegate将逻辑移至 SceneDelegate(参考:ios-scene-delegate)
热启动正常,冷启动却进入主页监听器注册过晚,或自定义 SceneDelegate 代码忽略了 connectionOptions在引导启动时调用 getLaunchUrl();保留 SceneDelegateProxy.shared.scene(_:willConnectTo:options:)
Safari cannot open the page because the address is invalid已安装的构建中未注册自定义 scheme添加 CFBundleURLTypes,然后重新构建(不能只运行 cap sync)
Error: Activity not started, unable to resolve Intent没有 intent-filter 与 scheme/host 匹配修正 <data> 条目;重新安装应用
pm get-app-links 显示 1024 或 none无法访问 assetlinks.json、软件包错误,或 SHA-256 错误(通常是 Play App Signing 密钥)修正文件,然后运行 adb shell pm verify-app-links --re-verify com.example.app
Android 对 https 链接显示应用选择器域名未验证(缺少 autoVerify 或验证失败)添加 android:autoVerify="true",然后重新验证
OAuth 重定向返回浏览器标签页,而非应用重定向 URI 与已注册的 scheme / 已验证域名不匹配注册确切的重定向 URI;优先使用已验证的 https 链接

资源

评论

支持 Markdown