mcpField
C
capacitor-deep-linking

capacitor-deep-linking

github.com/cap-go開発731.3k 回インストール2 週間前に更新
リポジトリ

capacitor-deep-linking について

Capacitor アプリの開発者向けに、カスタムスキーム、iOS Universal Links、Android App Links の設定と調査を支援するスキルです。コールド/ウォーム起動時の URL 処理や iOS の SceneDelegate にも対応します。

主な機能

  1. 01カスタムスキームと検証済みリンクの設定
  2. 02コールド/ウォーム起動 URL の処理
  3. 03iOS SceneDelegate ライフサイクルへの対応
  4. 04リンクとプラットフォーム設定の検証
  5. 05OAuth などのリダイレクト調査

活用シーン

  1. 01OAuth や決済のコールバックをアプリへ戻す
  2. 02アプリ起動後にホーム画面が開く問題の修正
  3. 03Android のドメイン検証失敗の診断
  4. 04Capacitor 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 の Universal Links、Android の App Links を Web アプリにルーティングします。

使用する場面

次の場合に使用します:

  • Capacitor アプリに myapp:// スキーム、Universal Links、または App Links を追加する
  • リンクを開くとアプリではなくブラウザーが開く、またはアプリは開くがホームページに移動する
  • ウォーム起動では appUrlOpen が発火するが、コールド起動では URL が取得できない(またはその逆)
  • Capacitor 8.5 以降への更新後、または SceneDelegate.swift の採用後にディープリンクが動作しなくなった
  • OAuth/マジックリンク/決済のリダイレクトでアプリに戻る必要がある
  • adb shell pm get-app-links の結果が verified ではなく none または 1024 になる

使用しないでください:

  • アプリ全体の AppDelegate から SceneDelegate への移行:capacitor-uiscene-migration
  • 通知タップのルーティング:capacitor-push-notifications
  • デバッグ時のネイティブログの取得:ios-android-logs
  • Sign in with Apple/Google プラグインの設定:capacitor-plugins

リンクの種類

種類プラットフォーム形式ホストされたファイルが必要所有権の検証
カスタムスキーム両方myapp://product/123いいえいいえ(どのアプリでも登録可能)
Universal LinksiOShttps://example.com/product/123/.well-known/apple-app-site-associationはい
App LinksAndroid 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 コアでは引き続き 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 は、最初のセグメントが pathname ではなく host として解析されます。上記のように両方の形式を正規化してください。
  • リスナーは遅延読み込みされるページ内ではなく、起動時に登録してください。イベントの発火後に追加したリスナーはイベントを受け取れません。コールドスタート時は getLaunchUrl() が代替手段になります。
  • リスナーからの状態更新は、フレームワークのゾーン/実行ループ(Angular の NgZone.run)でラップしてください。そうしないと、ナビゲーションが何も行わずに終わります。
  • 重複を排除してください:コールドスタート時は getLaunchUrl() と appUrlOpen の両方から URL を取得できる場合があります。
  • ナビゲーションの前にパスを検証し、許可リストと照合してください。ディープリンクは信頼できない入力です。

カスタムスキームの設定

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" は維持してください):

<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>

検証

すべてのケースを実機で実行してください(ユニバーサルリンクはシミュレーターのアドレスバーからは安定して動作しないため、代わりにメモまたはメッセージからタップしてください)。

シナリオiOSAndroid
カスタムスキーム、ウォームxcrun simctl openurl booted "myapp://product/123"adb shell am start -W -a android.intent.action.VIEW -d "myapp://product/123" com.example.app
カスタムスキーム、コールドアプリを終了してから、同じコマンドを実行adb shell am force-stop com.example.app を実行してから、同じコマンドを実行
検証済みリンク、ウォームメモで https://example.com/product/123 をタップadb 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(_:openURLContexts:)/scene(_:continue:))とは異なるネイティブパス(scene(_:willConnectTo:options:))を通ります。

移行後に残っている古いハンドラーを grep で検索します。

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

エラー処理

症状/メッセージ原因修正方法
アプリをインストール済みなのにリンクが Safari で開くAASA が取得されていない、appID が間違っている、エンタイトルメントがない、またはユーザーがリンクを長押しして「Safari で開く」を選択したApple CDN 経由で AASA を確認し、TEAMID.bundleId と applinks: エンタイトルメントを確認します。リンクを長押しして「アプリで開く」を選択し、設定をリセットします
8.5 への更新後、カスタム AppDelegate の URL コードが実行されなくなったシーンマニフェストが存在するため、iOS は SceneDelegate を呼び出しますロジックを SceneDelegate に移します(参考:ios-scene-delegate)
ウォームオープンは動作するが、コールド起動でホーム画面が開くリスナーの登録が遅い、またはカスタム SceneDelegate コードが connectionOptions を無視している起動時に getLaunchUrl() を呼び出し、SceneDelegateProxy.shared.scene(_:willConnectTo:options:) を維持します
Safari cannot open the page because the address is invalidインストール済みビルドでカスタムスキームが登録されていないCFBundleURLTypes を追加して再ビルドします(cap sync だけでは不十分です)
Error: Activity not started, unable to resolve Intentスキーム/ホストに一致するインテントフィルターがない<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 が登録済みのスキーム/検証済みドメインと一致しない正確なリダイレクト URI を登録します。検証済みの https リンクを推奨します

リソース

コメント