capacitor-app-intents について
Capacitor アプリに iOS のネイティブ App Intents を追加し、フォアグラウンド操作を Web 層につなぐためのスキルです。コールド起動時のルーティングやバックグラウンド実行の制約も扱います。
主な機能
- 01ネイティブ Swift App Intents の設定
- 02フォアグラウンド Intent の Web 層へのルーティング
- 03バックグラウンド Intent の制約
- 04ショートカット、ウィジェット、コントロール
- 05OS バージョンに応じた API の案内
- 06ビルドとデバイスでの検証
活用シーン
- 01Siri やショートカット操作の追加
- 02Intent のコールド起動ルーティング
- 03ヘッドレス Intent の障害調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ cap-go/ capgo-skills --skill capacitor-app-intentsインストール後、Claude Code で/capacitor-app-intentsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.jsonreferences/intent-traps.mdios-26-27-apis.mdproject-setup.mdweb-bridge.mdwidgets-and-controls.md詳細
Capacitor アプリ向け App Intents
iOS プロジェクトにネイティブの App Intents を追加して、システム上の各所からアプリのアクションを実行できるようにし、ウェブレイヤーと接続します。App Intents は Swift 専用です。JavaScript API はないため、すべてのインテントは App ターゲットまたは拡張機能内のネイティブコードで実装し、URL または小規模なローカルプラグインを介してウェブレイヤーにアクセスします。
使用する状況
次の場合に使用します:
- ユーザーが、Capacitor アプリに Siri のフレーズ、ショートカットのアクション、App Shortcuts、Spotlight のアクション、アクションボタン、または Apple Intelligence との連携を追加したい
- ユーザーが、ウィジェットのボタンまたはコントロールセンターのコントロールからアプリのアクションを実行したい
- インテントでアプリは開くものの、Web ビューが遷移しない、またはアプリのウォーム起動時にしか遷移しない
- バックグラウンドインテントがクラッシュする、タイムアウトする、または JS を呼び出そうとする
openAppWhenRunからsupportedModesに移行する、または iOS 26/27 の App Intents API を採用する- プラグインの作成者が App Intents をプラグインに同梱したい
使用しない場合:
- Universal Links/カスタムスキーム/
appUrlOpenの設定:capacitor-deep-linking - AppDelegate から SceneDelegate への移行:
capacitor-uiscene-migration - プッシュ通知のアクション:
capacitor-push-notifications - JS から駆動する Live Activities または SVG ウィジェット:
capacitor-plugins(@capgo/capacitor-widget-kit) - Android のアプリショートカットとインテント:対象外です
設計の前提となる事実
- App Intents には iOS 16 が必要です。 Capacitor 8 のデプロイ対象は iOS 15 であるため、すべてのインテント型、エンティティ、クエリ、
AppShortcutsProviderに@available(iOS 16.0, *)を指定するか、ユーザーがデプロイメントターゲットを引き上げる必要があります。Capacitor 9 のデプロイ対象は iOS 16 であるため、基本 API に条件指定は不要です。新しい API には引き続き必要です(references/ios-26-27-apis.md の表を参照)。 - バックグラウンドインテントでは WebView を利用できません。 iOS は
.backgroundインテントのために、アプリのプロセスをヘッドレスで起動できます。AppDelegate.application(_:didFinishLaunchingWithOptions:)は実行されますが、シーンは接続されず、CAPBridgeViewControllerも読み込まれません。バックグラウンドインテントでは、ネイティブ処理(ネットワーク、ストレージ、HealthKit など)のみを実行する必要があります。ブリッジ経由で JS やプラグインを呼び出すことはできません。 perform()はメインアクター上では実行されず、複数回実行される可能性があります。 UIKit、ブリッジ、または@MainActorの状態に触れる前に、明示的に切り替えます(await MainActor.runまたは@MainActor func perform())。元に戻せない処理は最後に実行します。詳細はreferences/intent-traps.mdを参照してください。- UIScene(Capacitor 8.5 以降)では、URL の受け渡し先が変わっています。 Universal Links とカスタムスキームによる起動は
SceneDelegateに届き、SceneDelegateProxyによって転送されます。これにより、@capacitor/appがリッスンする通知が投稿されます。アプリにAppDelegate内のカスタム URL コードが残っていても、もう実行されません。通常のリンクでappUrlOpenが発火しない場合は、まずcapacitor-deep-linkingを確認してください。インテントでは、壊れたリンク処理を修正できません。 - コールド起動時には、JS リスナーはまだ存在しません。 インテントからウェブレイヤーに渡すルートは、JS が取得するまで保持する必要があります。URL には
App.getLaunchUrl()を、ローカルプラグインを使う場合は保留ルートストアとnotifyListeners(..., retainUntilConsumed: true)を使用してください。 - 識別子は公開された契約です。 インテント型の名前、
AppEntity.idの値、AppEnumの raw 値、URL 形式、公開済みのフレーズは、ユーザーが保存したショートカットに記録されます。新しいものを追加し、ユーザーに知らせずに公開済みのものを変更または削除しないでください。
参考資料
トピックが関係する場合にのみ、参考資料を読み込んでください。
| ファイル | 読み込むタイミング |
|---|---|
| references/project-setup.md | ファイルの作成、ターゲットへの所属、拡張機能、App Groups、利用可能性の条件分岐、ビルド検証 |
| references/web-bridge.md | インテントをウェブレイヤーに接続するとき:URL ルーティング、ローカルの AppIntentsBridge プラグイン、保留中のルート、共有データ |
| references/intent-traps.md | インテント、エンティティ、クエリ、フレーズ、依存関係、エラー、寄付を作成またはレビューするとき |
| references/ios-26-27-apis.md | supportedModes、フォアグラウンドでの継続、長時間実行・キャンセル可能・取り消し可能なインテント、実行ターゲット、スニペット、Spotlight のインデックス作成、スキーマ、テスト |
| references/widgets-and-controls.md | ウィジェット設定インテント、インタラクティブなウィジェットボタン、コントロールセンターのコントロール |
ワークフロー
1. 調査(読み取り専用)
package.json(@capacitor/iosのバージョン)、ios/App/App/Info.plist(シーンマニフェストがあるか)、ios/App/App/AppDelegate.swift、ios/App/App/SceneDelegate.swift、App ターゲットのデプロイメントターゲット、既存の*.entitlements(Associated Domains、App Groups)を確認します。- アプリが JS でディープリンクをすでに処理しているか(
App.addListener('appUrlOpen', ...)、App.getLaunchUrl())、またどのルートがあるかを確認します。 - 既存のインテントを検索します:
grep -rn "AppIntent\|AppShortcutsProvider\|openAppWhenRun" ios/App。 ios/App/App.xcodeproj/project.pbxprojの拡張ターゲット(ウィジェット)を一覧表示します(App以外のPBXNativeTargetエントリ)。
2. ユーザーと設計する
ユーザーが希望するアクションごとに、次の項目を決定して確認します。
| 質問 | 選択肢 |
|---|---|
| UI が必要ですか? | いいえ:バックグラウンドインテント、ネイティブのみ。はい:ウェブアプリにルーティングするフォアグラウンドインテント |
| JS にどう接続しますか? | OpenURLIntent によるユニバーサルリンク(iOS 18 以降、Associated Domains が必要)、または保留中ルート用ストアを備えたローカルプラグイン(カスタムスキームと iOS 16 以降で動作) |
| 必要なデータは何ですか? | 固定セット:AppEnum。動的でクエリ可能:AppEntity + EntityQuery。自由記述テキストまたは数値:通常の @Parameter |
| どこで実行する必要がありますか? | App ターゲットのみ、またはウィジェット/コントロールでも実行(その場合、インテントファイルは両方のターゲットに所属させる必要があります) |
| どのサーフェスで使いますか? | App Shortcut のフレーズ(アプリあたり最大 10 個の App Shortcut)、Spotlight、ウィジェット、コントロール |
タスクの単位ごとにインテントを 1 つにします。編集前に、計画(追加するファイル、ターゲット、エンタイトルメント、JS の変更)を報告します。
3. 実装
- App ターゲットに所属させた Swift ファイルを
ios/App/App/Intents/に作成します(references/project-setup.md)。 - references/intent-traps.md に従ってインテントを記述します。API はバージョンに応じて条件分岐します。
- ウェブブリッジを追加します(references/web-bridge.md):ディープリンクルーターを再利用するか、ローカルプラグインを追加して
CAPBridgeViewControllerのサブクラスに登録します。 - すべてのフレーズに
shortTitle、systemImageName、\(.applicationName)を含めたAppShortcutsProviderを追加します。 - 必要な場合にのみエンタイトルメントを追加します(共有データには App Groups、ユニバーサルリンクには Associated Domains)。使用するすべてのターゲットに設定します。
- JS 側:ウォームスタート時とコールドスタート時にルートを処理します。
4. 検証
npx cap sync ios
xcodebuild -project ios/App/App.xcodeproj -scheme App \
-destination 'generic/platform=iOS Simulator' build
# CocoaPods projects: -workspace ios/App/App.xcworkspace
- ビルドログに App Intents メタデータ抽出のステップが表示され、フレーズに関する警告がないことを確認します。
\(.applicationName)を含まないフレーズはビルド警告を発生させ、実行時に無視されます。 - Xcode の「Product」>「App Shortcuts Preview」で、フレーズが一致することを確認します。
- シミュレーターまたはデバイスで実行します。「ショートカット」アプリを開き、アプリのアクションを探して、それぞれ実行します。
- バックグラウンドインテント:アプリが前面に表示されずに完了します。ネイティブログ(
ios-android-logs)を確認します。 - フォアグラウンドインテント:アプリを終了した状態(コールド)と実行中の状態(ウォーム)の両方で、Web ビューが正しいルートに移動することを確認します。
- バックグラウンドインテント:アプリが前面に表示されずに完了します。ネイティブログ(
- Spotlight:ショートカットのタイトルを検索します。
- テストがある場合は、iOS 27 のテストランナー向けに AppIntentsTesting のカバレッジを追加します(references/ios-26-27-apis.md)。
エラー処理
| 症状 | 原因 | 解決方法 |
|---|---|---|
'AppIntent' is only available in iOS 16.0 or newer | Capacitor 8 プロジェクトのデプロイ先が iOS 15 | すべての App Intents 型に @available(iOS 16.0, *) を追加するか、ユーザーの承認を得てデプロイメントターゲットを引き上げます |
| インストール後、インテントが「ショートカット」に表示されない | ファイルが App ターゲットに含まれていない、またはメタデータの抽出に失敗した | ターゲットメンバーシップを確認します。App Intents メタデータのステップについてビルドログを確認し、アプリを再インストールします |
| Siri でフレーズがまったく起動しない。ビルド時にアプリ名に関する警告が表示される | フレーズに \(.applicationName) がない | すべてのフレーズにトークンを追加します |
| App Shortcuts が 10 個を超えるというビルドエラー | アプリごとの上限 | アクションを統合するか、重要度の低いものを削除します |
@Dependency によるアクセス時に「...was not initialized prior to access」でクラッシュする | 依存関係の登録が遅すぎる(ビューコントローラー内) | ヘッドレス起動時にも実行される AppDelegate.application(_:didFinishLaunchingWithOptions:) で登録します |
| フォアグラウンドインテントでアプリは開くが、コールドスタート時に Web ビューがホームルートのままになる | JS がリスナーを追加する前にルートが送信された | 保留ルートストアと retainUntilConsumed、または App.getLaunchUrl() を使用します |
OpenURLIntent で appUrlOpen がまったく発生しない | Universal Links が設定されていない、または UIScene のもとでカスタム AppDelegate URL コードを使用している | capacitor-deep-linking で修正します。OpenURLIntent には実際の https Universal Link が必要です |
| Swift 6 エラー:メインアクターに隔離されたプロパティが、非隔離の要件を満たせない | インテント型に @MainActor が付いている | 型から @MainActor を削除します。perform() に付けるか、その内部で切り替えます |
| バックグラウンドインテントが約 30 秒後に終了させられる | バックグラウンドインテントに対する iOS の制限 | 処理を短縮するか、iOS 27 では LongRunningIntent を使用します |
'openAppWhenRun' was deprecated in iOS 26.0 | iOS 26 SDK | 条件付きの supportedModes を追加します(references/ios-26-27-apis.md)。デプロイメントターゲットが 26 未満の間は openAppWhenRun を残します |
関連スキル
capacitor-deep-linking:インテントが依存する Universal Links とappUrlOpenのルーティングcapacitor-uiscene-migration:Xcode 27 より前に必要です。URL 処理をSceneDelegateに移しますcapacitor-plugins:Live Activities と JS 駆動のウィジェット向けの@capgo/capacitor-widget-kitcapacitor-testing:ネイティブユニットテストとデバイス検証の手順ios-android-logs:ヘッドレスインテント実行時のログ
コメント
Markdown 対応