Capacitorアプリ用のApple Watchアプリを構築するには、iOSプロジェクトにネイティブのwatchOSターゲットを追加し、SwiftUIでUIを書き、Web codeと接続します。 @capgo/capacitor-watch plugin, which wraps Apple’s WatchConnectivity framework. The phone app keeps its Capacitor web layer, and the watch app becomes a small native companion that sends and receives dictionaries.
このガイドでは、Capacitor 8とXcode 26のフルパスをカバーします: アーキテクチャ、Xcodeターゲット、SwiftとTypeScript codeの両方の側面、転送方法、シミュレータとデバイスでのテスト、およびウォッチアプリの配信方法について説明します。
なぜウォッチのUIはネイティブで、電話はCapacitorのままなのでしょう。
watchOSはWebViewを搭載していない。 WKWebView watchOSにはWebViewが搭載されていないため、Capacitorアプリはそこで実行できず、プラグインの変更もできない。代わりに、責任を分割することができる。
| Layer | 実行される場所 | 言語 | Job |
|---|---|---|---|
| Capacitorアプリ | iPhone | TypeScript、選択したフレームワーク | ビジネスロジック、ネットワーク、認証、ストレージ |
@capgo/capacitor-watch |
iPhone | Swift (プラグイン), JS API | WatchConnectivityをJavaScriptに橋渡し |
| CapgoWatchSDK | Apple Watch | Swift | 腕時計セッションの管理 |
| 腕時計アプリ | Apple Watch | SwiftUI | 小さな画面、見やすいUI、迅速なアクション |
実際には腕時計アプリは「依存」である:腕時計はデータを電話から取得する。TypeScriptで既存のロジックを電話に保ち、腕時計に表示する必要があるデータのみを送信する。
前提条件
- A Capacitor 8アプリにiOSプラットフォームを追加しました。まだ古いバージョンにいる場合は、Capacitor 8アップグレードガイドを参照してください。 Capacitor 8アップグレードガイド 最初に
- MacでXcode 26を使用します。Appleは2026年4月以降、App StoreへのアップロードにXcode 26を必要とします。詳しくはXcode 26の要件を参照してください。 Xcode 26の要件.
- Apple Developerアカウントが必要です。デバイスのテストと配布に使用します。
- iOS 15以降の電話 (プラグインの最小限) とwatchOS 9以降の腕時計 (SDK の最小限) が必要です。
- 実際には、実際のiPhoneと実際のApple Watchが最適です。シミュレータは役立ちますが、すべての転送タイプをカバーしません。
ステップ 1:電話側にプラグインをインストールする
bun add @capgo/capacitor-watch
bunx cap sync ios
コンテキスト:Capgoのページ。役割:UIラベル。見られる場所:about.astroのページ。メッセージキー`about_how_step_label` (About How Step Label)。 WCSession プラグインはロードされたときに自動的に有効になります。初期化呼び出しはありません。接続状態を読み始めてください。
import { CapgoWatch } from '@capgo/capacitor-watch';
const info = await CapgoWatch.getInfo();
console.log({
supported: info.isSupported, // false on iPad, Android without Wear OS, and web
paired: info.isPaired, // an Apple Watch is paired with this iPhone
installed: info.isWatchAppInstalled, // your watch app is on that watch
reachable: info.isReachable, // live messaging is possible right now
state: info.activationState, // 0 notActivated, 1 inactive, 2 activated
});
APIは完全なリファレンスが存在します。 プラグインドキュメント そして プラグインページ.
ステップ2:XcodeでwatchOSターゲットを追加する
iOSプロジェクトを開く bunx cap open iosCapacitor 8プロジェクトはSwift Package Managerで作成されました App.xcodeproj古いCocoaPodsプロジェクトを開く App.xcworkspaceどちらでもかまいません
- ファイル 新規作成ターゲット watchOS タブを切り替え、次に アプリ.
- 名前を付けましょう。例えば
MyWatch, そして SwiftUI をインターフェイスとして使用します。 - オプションシートで、ウォッチアプリを既存の
Appターゲットに伴侶として埋め込まれていることを確認してください。 その設定がXcodeがウォッチアプリをiPhoneビルドに埋め込むのに役立ち、伴侶のバンドル識別子を設定するのに役立ちます。 - 通知シーンや複雑さをオフにしないでください。必要な場合は後で追加できます。
- 新しいスキームを有効にするためのプロンプトを受け入れてください。
バンドル識別子規則
ウォッチアプリのバンドルIDはiPhoneアプリのバンドルIDで始まる必要があります。アプリが com.example.shop、Xcodeが提案します com.example.shop.watchkitappiOSのバンドルIDを後で変更した場合、時計のバンドルIDも変更する必要があります。そうしないと、ビルドが検証に失敗し、WatchConnectivityが2つのアプリをペアリングできなくなります。
下の 署名 & 能力に移動して、両方のターゲットに同じチームを選択してください。自動署名の場合、Xcodeは2番目のApp IDとプロビジョニングプロファイルを登録します。
時計ターゲットにCapgoWatchSDKを追加します
- ファイル>パッケージ依存関係を追加.
- にエンターします
https://github.com/Cap-go/capacitor-watch.git. - 「次のメジャーバージョンまで」を選択してください
8.0.0. - Xcodeがどの製品を追加するか尋ねたら、次の製品のみを選択してください CapgoWatchSDK とAssignします watch 対象は、iOSアプリではなく、Apple Watchアプリです。iOS側はすでにプラグインを取得しています。
cap sync.
ステップ3: Apple WatchアプリをSwiftUIで作成する
SDKが公開します。 WatchConnector.sharedCapgoは ObservableObject 、 isReachable, isActivated, lastMessage、 applicationContext プロパティを公開します。アプリが起動したときに有効にします:
import SwiftUI
import CapgoWatchSDK
@main
struct MyWatchApp: App {
init() {
WatchConnector.shared.activate()
}
var body: some Scene {
WindowGroup {
OrdersView()
}
}
}
小さな画面で、電話からデータを送信し、電話にアクションを送信します:
import SwiftUI
import CapgoWatchSDK
struct OrdersView: View {
@ObservedObject private var connector = WatchConnector.shared
@State private var status = ""
var openOrders: Int {
connector.applicationContext["openOrders"] as? Int ?? 0
}
var body: some View {
VStack(spacing: 8) {
Text("\(openOrders)")
.font(.system(size: 44, weight: .bold))
Text("open orders")
.font(.footnote)
.foregroundStyle(.secondary)
Button("Refresh") {
refresh()
}
.disabled(!connector.isReachable)
if !status.isEmpty {
Text(status).font(.caption2)
}
}
}
private func refresh() {
Task {
do {
let reply = try await connector.sendMessage(["action": "refresh"])
status = "Updated \(reply["count"] as? Int ?? 0)"
} catch {
status = "iPhone not reachable"
}
}
}
}
Capgoの async のバリエーションは sendMessage を送信し、返信ハンドラーが付いています。電話はこれを返信ハンドラーとして受け取ります。 messageReceivedWithReply イベント。コールバックベースのバリアント sendMessage(_:replyHandler:errorHandler:) 返信をスキップできます。
デリゲートコールバックを観察されたプロパティよりも好みの方がいる場合、 WatchConnectorDelegate を実装し、 WatchConnector.shared.delegateを設定します。メッセージ、返信ハンドラー付きメッセージ、
アプリケーションコンテキスト、ユーザー情報、リーチャビリティ、
アクティベーションに使用できるメソッドがあります。
import { CapgoWatch } from '@capgo/capacitor-watch';
export async function setupWatchBridge(getOpenOrders: () => Promise<number>) {
// Watch asked for something and is waiting for an answer
await CapgoWatch.addListener('messageReceivedWithReply', async (event) => {
if (event.message.action === 'refresh') {
const count = await getOpenOrders();
await CapgoWatch.replyToMessage({
callbackId: event.callbackId,
data: { count },
});
await pushStateToWatch(count);
}
});
// Fire-and-forget messages from the watch
await CapgoWatch.addListener('messageReceived', (event) => {
console.log('watch says', event.message);
});
await CapgoWatch.addListener('reachabilityChanged', (event) => {
console.log('watch reachable:', event.isReachable);
});
await pushStateToWatch(await getOpenOrders());
}
export async function pushStateToWatch(openOrders: number) {
const info = await CapgoWatch.getInfo();
if (!info.isSupported || !info.isPaired || !info.isWatchAppInstalled) return;
// Latest state only, delivered when the watch app next runs
await CapgoWatch.updateApplicationContext({
context: { openOrders, updatedAt: Date.now() },
});
}
ステップ 4: watch から TypeScript で話す messageReceivedWithReplyページ/エリア: Capgo のページ。役割: UI ラベル。見られる場所: about.astro のページ。メッセージキー `about_how_step_label` (About How Step Label)。
リスナーを早く登録してください。例えば、初期化時にアプリの起動時に到着するイベントを失うのを避けるために。
常に返信を
| Method | 配信 | 時計が届く | 適している |
|---|---|---|---|
sendMessage |
即時 | はい、否定の場合 | 両方のアプリが開いている間のボタンタップとライブアップデート |
updateApplicationContext |
最新の値が優先され、可能な限り配信される | いいえ | 現在の状態: カウント、設定、ログインユーザー |
transferUserInfo |
キューイング、順序に従って配信 | いいえ | すべて到着する必要があるイベント: ログインしたワークアウト、作成されたレコード |
アプリケーション コンテキストを、ウォッチが表示する内容の真実の源として使用するパターンが効果的です。アプリケーション コンテキストを使用して、ウォッチが表示する内容を決定します。 sendMessage watchアプリが開いている間のみの操作に使用 transferUserInfo 失敗を恐れずに挑戦する。
Designの制約
- ペイロードサイズ。 WatchConnectivityは大きすぎるpayloadを拒否し、
payloadTooLargeAppleは各チャネルごとの固定バイト数を公開していません。payloadを小さくしてください: ID、数値、短い文字列。大きいコンテンツはAPIから取得してください。 - ペイロードのタイプ。 データはプロパティリスト互換性があります:文字列、数値、ブール値、日付、データ、配列、辞書。
nullJavaScriptから取得した値は有効ではありません。送信する前に削除してください。 - 電話はアプリを実行している必要があります。イベントを処理する リスナーはCapacitor JavaScript runtimeに存在します。iOSがアプリを終了した場合、イベントは再びアプリが実行されるまでTypeScriptに届きません。コンテキストとユーザー情報はシステムによってキュー化されますが、キャッシュされたコンテキストで動作するようにウォッチUIを設計してください。
- ペアリング。 Apple WatchはiPhoneのみとペアリングします。Androidユーザーは使用できず、プラグインのAndroid実装はWear OSを対象としており、Wear OSガイドで説明されています。 Wear OSガイド.
- 独立性。 WatchConnectivityを使用したコンパニオンアプリは電話に依存します。ウォッチが電話から離れた場所で動作する必要がある場合は、ウォッチのネットワーク接続を使用して独自のAPIを追加してください。
シミュレータとデバイスのテスト
ウォッチシミュレータでSwiftUIレイアウトを繰り返し実行できますが、データ転送にはペアリングされたセットアップが必要です。
xcrun simctl list devices
xcrun simctl pair <watch-udid> <phone-udid>
iOSアプリをペアリングされたiPhoneシミュレータで実行し、ウォッチシミュレータでウォッチスキームを実行します。両方のアプリがインストールされている必要があります。 isWatchAppInstalled 実行されることが真実になる前に。 transferUserInfoAppleは、Simulatorはサポートしていないため、実機で確認してください。
デバイスの場合、iPhoneを接続し、ウォッチの開発者モードを有効にし、ウォッチスキームの実行先としてウォッチを選択します。Smoke Testとして使用します: getInfo() あなたのSmokeテスト:
getInfo() 結果 |
意味 |
|---|---|
isPaired: false |
この電話とペアされていない腕時計 |
isWatchAppInstalled: false |
腕時計アプリが見つかりません、またはバンドID/コンパニオン設定が間違っています |
isReachable: false, 真実 |
腕時計アプリがフォアグラウンドに表示されていない、または範囲外 |
activationState: 2, 全て真実 |
準備 sendMessage |
トラブルシューティング
isWatchAppInstalled コンテキスト: サポート/プレミアムサポートページまたはフッターのサポートセクション。役割: セクションまたはページヘッダー。見られる場所: サポートポリシーページ。メッセージキー `support_policy_troubleshooting_title` (サポートポリシー トラブルシューティング タイトル)。 真実 App 腕時計のバンドIDのプレフィックスを確認し、腕時計のターゲットがビルドフェーズ > Embed Watch Content に埋め込まれていることを確認し、両方のアプリを再インストールしてください。
時計から送信されるメッセージは、JavaScriptに届きません。 時計が送信する前にリスナーを登録し、時計が起動したときに時計が呼び出すことを確認します。電話で、Xcodeコンソールでプラグインのアクティベーションログを確認してください。 WatchConnector.shared.activate() 時計が起動したときに時計が呼び出すことを確認します。電話で、Xcodeコンソールでプラグインのアクティベーションログを確認してください。
sendMessage 時計が届かない場合に期待される。時計アプリが閉じられている場合。 予想される時計アプリが閉じられている場合。時計アプリが閉じられている場合にフォールバックします。 updateApplicationContext.
replyToMessage 時計のアプリが閉じられている場合に期待される。 イベントから正確に callbackId イベントから正確に
時計のアプリが閉じられている場合に期待される。 時計のアプリが閉じられている場合に期待される。
時計のアプリが閉じられている場合に期待される。 時計のアプリが閉じられている場合に期待される。 Assets.xcassets.
Apple Watchアプリを配信する
Apple Watchアプリは別の製品ではありません。iOSアーカイブに埋め込まれ、共にアップロードされ、同じApp Store Connectレコードに表示されます。そこで、Apple Watchのスクリーンショットを追加するためのタブがあります。アーカイブを生成するものは何でも、ローカルXcode、CI、または Capgo ビルドアップデートには注意してください。
Capgoライブアップデート Capgo ライブアップデート can ship changes to the phone’s web bundle without a store review, which is handy when the TypeScript side of your watch bridge has a bug. Swift code on the watch, and any change to the native plugin, still goes through the App Store. Version your message format, for example with a v すべての辞書にフィールドがあるため、最新のスマートフォンと古いウォッチのバージョンで機能するパッケージが作成されます。
クレジット
Capacitorビルド @capgo/capacitor-watch__CAPGO_KEEP_0__ライブアップデート