Zum Hauptinhalt springen

Wie man eine Apple Watch App für eine Capacitor App erstellt

Erstelle eine Apple Watch-App für deine Capacitor-App: Füge einen watchOS-Ziel hinzu, schreibe die SwiftUI-Seite und synchronisiere die Daten mit dem iPhone mithilfe von @capgo/capacitor-watch.

Artikelcredits

Martin Donadieu

Schreiber

Valeria

Reviewer

Jordan

Editor

Wie man eine Apple Watch App für eine Capacitor App erstellt

Um eine Apple Watch App für eine Capacitor App zu erstellen, fügen Sie einem iOS-Projekt eine native watchOS-Zielgruppe hinzu, gestalten Sie die Benutzeroberfläche in SwiftUI und verbinden Sie sie mit Ihrem Web-code mithilfe des @capgo/capacitor-watch Plugins, das Apple's WatchConnectivity-Framework umschließt. Das Telefon-App bleibt bei seiner Web-Capacitor-Layer und die Uhr-App wird zu einem kleinen nativen Begleiter, der Wörterbücher sendet und empfängt.

Diese Anleitung umfasst den gesamten Weg auf Capacitor 8 und Xcode 26: die Architektur, das Xcode-Ziel, die Swift- und TypeScript-code auf jeder Seite, die Übertragungsmethode, die Testung auf Simulatoren und Geräten und wie die Uhr-App verschickt wird.

Warum ist die Uhr-Oberfläche native und bleibt der Telefon-Bildschirm Capacitor

watchOS liefert keine WebView. Es gibt keine WKWebView auf der Uhr, also kann keine Capacitor-App dort laufen und kein Plugin ändert das. Was Sie tun können, ist die Verantwortlichkeiten aufteilen:

Schicht Läuft auf Sprache Aufgabe
Capacitor-App iPhone TypeScript, Ihre Framework-Choice Geschäftslogik, Netzwerk, Auth, Speicher
@capgo/capacitor-watch iPhone Swift (Plugin), JS API Verbindet WatchConnectivity mit JavaScript
CapgoWatchSDK Apple Watch Swift Sitzungsverwaltung auf dem Uhren
Uhrenanwendung Apple Watch SwiftUI Kleine Bildschirme, Blickfang-UI, schnelle Aktionen

In der Praxis ist die Uhrenanwendung „abhängig“: Sie erhält ihre Daten vom Telefon. Halten Sie die Logik auf dem Telefon, wo sie bereits in TypeScript existiert, und senden Sie der Uhr nur das, was sie anzeigen muss.

Voraussetzungen

  • Ein Capacitor 8-App mit der iOS-Plattform hinzugefügt. Wenn Sie noch auf einer älteren Version sind, folgen Sie bitte dem Capacitor 8-Upgrade-Leitfaden erst.
  • Xcode 26 auf einem Mac. Apple hat seit April 2026 Xcode 26 für die App-Store-Uploads erforderlich, siehe die Xcode 26-Anforderung.
  • Ein Apple-Entwicklerkonto für die Geräteprüfung und -verteilung.
  • iOS 15 oder höher auf dem Telefon (die Plugin-Mindestversion) und watchOS 9 oder höher auf dem Uhr (die SDK-Mindestversion).
  • Idealerweise ein echter iPhone mit einem echten Apple Watch. Simulatoren helfen, aber sie decken keine Übertragungstypen ab.

Schritt 1: Installieren Sie das Plugin auf der Telefonseite

bun add @capgo/capacitor-watch
bunx cap sync ios

Der Plugin aktiviert WCSession sobald es geladen ist, gibt es also keine Init-Anforderung. Beginnen Sie mit der Lesung des Verbindungszustands:

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
});

Die vollständige API-Referenz befindet sich in den plugin docs und den Plugin-Seiten.

Schritt 2: Fügen Sie einen watchOS-Ziel in Xcode hinzu

Öffnen Sie das iOS-Projekt mit bunx cap open ios. Capacitor 8 Projekte mit Swift Package Manager geöffnet App.xcodeproj. Alternativ können ältere CocoaPods-Projekte geöffnet werden App.xcworkspace. Ebenfalls funktioniert das.

  1. Wählen Sie Datei > Neues Projekt > Ziel, wählen Sie die watchOS -Sektion, dann App.
  2. Benennen Sie es, zum Beispiel MyWatch, und verwenden SwiftUI als die Schnittstelle.
  3. In der Optionsschaltfläche stellen Sie sicher, dass die Uhranwendung in Ihrem bestehenden App Das Ziel wird als Begleiter festgelegt. Diese Einstellung ist es, die Xcode die Uhranwendung im iPhone-Build einbetritt und die Begleiter-Bundle-Identifikator festlegt.
  4. Deaktivieren Sie Benachrichtigungsszenarien und Komplikationen, es sei denn, Sie benötigen sie jetzt. Sie können Widgets später hinzufügen.
  5. Akzeptieren Sie die Aufforderung, die neue Scheme zu aktivieren.

Die Regel für die Bundle-Identifikator

Die Bundle-ID der Uhranwendung muss mit der Bundle-ID der iPhone-Anwendung beginnen. Wenn Ihre App com.example.shopXcode schlägt vor com.example.shop.watchkitapp. Halten Sie sich an diesen Präfix. Wenn Sie die iOS-Bundle-ID später ändern, ändern Sie auch die Uhranwendung, oder die Validierung wird fehlschlagen und WatchConnectivity wird die beiden Apps nicht pairn.

Unter Zertifizierung & FähigkeitenWählen Sie für beide Ziele dieselbe Mannschaft aus. Mit automatischer Signierung registriert Xcode die zweite App-ID und das Provisioning-Profil für Sie.

Add CapgoWatchSDK to the watch target

  1. Datei > Hinzufügen von Paketabhängigkeiten.
  2. Eingeben https://github.com/Cap-go/capacitor-watch.git.
  3. Verwenden Sie „Bis zur nächsten Hauptversion“ von 8.0.0.
  4. Wenn Xcode fragt, welche Produkte hinzufügen, wählen Sie nur CapgoWatchSDK und zuweisen Sie es der Uhr Ziel, nicht der iOS-Anwendung. Die iOS-Seite erhält den Plugin bereits durch cap sync.

Schritt 3: Erstellen Sie die Uhranwendung in SwiftUI

Das SDK stellt WatchConnector.sharedan, ObservableObject mit veröffentlichten isReachable, isActivated, lastMessageund applicationContext Eigenschaften. Aktivieren Sie es, wenn die App startet:

import SwiftUI
import CapgoWatchSDK

@main
struct MyWatchApp: App {
    init() {
        WatchConnector.shared.activate()
    }

    var body: some Scene {
        WindowGroup {
            OrdersView()
        }
    }
}

Eine kleine Anzeige, die Daten vom Telefon pushen und eine Aktion zurücksendet:

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

Die async Variante von sendMessage sendet mit einem Antworthandler, so dass das Telefon es als messageReceivedWithReply ereignis empfängt. Die callback-basierte Variante sendMessage(_:replyHandler:errorHandler:) lässt Sie das Antworten überspringen.

Wenn Sie Callbacks über die Beobachtung von publizierten Eigenschaften bevorzugen, entsprechen Sie sich WatchConnectorDelegate und setzen WatchConnector.shared.delegate. Es verfügt über Methoden für Nachrichten, Nachrichten mit einer Antwort-Handler, Anwendungs-Kontext, Benutzer-Info, Erreichbarkeit und Aktivierung.

Schritt 4: Sprechen Sie mit der Uhr aus TypeScript

Registrieren Sie sich frühzeitig, zum Beispiel in Ihrem App-Bootstrap, damit Ereignisse, die bei der Startphase eintreffen, nicht verpasst werden.

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() },
  });
}

Antworten Sie immer messageReceivedWithReplyDie Uhr wartet, und eine unbeantwortete Anfrage endet mit einem Timeout-Fehler auf der Uhr-Seite.

Welche Übertragungsmethode sollten Sie verwenden?

WatchConnectivity bietet Ihnen drei Kanäle, und der Plugin kartiert jeden davon:

Methode Zustellung Braucht Uhr erreichbar Gut für
sendMessage Unmittelbar Ja, sonst abgelehnt Tastereingaben, Live-Updates, während beide Apps geöffnet sind
updateApplicationContext Neuester Wert gewinnt, so schnell wie möglich geliefert Nein Aktueller Zustand: Zählungen, Einstellungen, angemeldeter Benutzer
transferUserInfo In der Warteschleife, in der Reihenfolge geliefert Nein Alle Ereignisse, die ankommen müssen: abgeschlossene Workouts, erstellte Aufzeichnungen

Ein Muster, das gut funktioniert: Verwenden Sie den Anwendungscontext als Quelle der Wahrheit für das, was der Uhr anzeigt, verwenden Sie sendMessage nur für Interaktionen, während die Uhranwendung geöffnet ist, und verwenden Sie transferUserInfo für alles, was Sie sich nicht leisten können, auszusetzen.

Grenzen, die man im Design berücksichtigen muss

  • Payload-Größe. WatchConnectivity lehnt Payloads ab, die zu groß sind, mit payloadTooLargeund Apple veröffentlicht keine feste Bytezahl für jeden Kanal. Halten Sie Payloads klein: IDs, Zählungen, kurze Zeichenketten. Laden Sie große Inhalte aus Ihrem API ab.
  • Payload-Typen. Daten müssen property-list-kompatibel sein: Zeichenketten, Zahlen, Boolesche Werte, Daten, Daten und Werte, Arrays und Wörterbücher. null Werte aus JavaScript sind nicht gültig. Entfernen Sie sie vor dem Senden.
  • Das Telefon muss Ihre App ausführen, um Ereignisse zu verarbeiten. Hörer leben im Capacitor JavaScript- Runtime. Wenn iOS die App beendet hat, werden Ereignisse nicht bis zu Ihrem TypeScript gelangen, bis die App wieder läuft. Kontext und Benutzerinformationen bleiben durch das System in der Warteschleife, aber gestalten Sie die Uhr-UI so, dass sie von einem gecacheten Kontext funktioniert.
  • Pairing. Ein Apple Watch kann nur mit einem iPhone pairt. Android-Nutzer können es nicht verwenden, und die Plugin-Implementierung für Android zielt auf Wear OS ab, das in unserem Wear OS-Leitfaden.
  • Unabhängigkeit. Auf einem auf WatchConnectivity basierenden Begleitapp benötigt man das Telefon. Wenn das Armband weit vom Telefon entfernt arbeiten muss, füge einen zweiten Datenquellen wie deine API über die Netzwerkverbindung des Armbands hinzu.

Testen auf Simulatoren und Geräten

Du kannst in der Armband-Simulator die SwiftUI-Anordnung iterieren, aber die Datenübertragung benötigt eine gepaarte Konfiguration.

xcrun simctl list devices
xcrun simctl pair <watch-udid> <phone-udid>

Laufe die iOS-App auf dem gepaarten iPhone-Simulator aus, dann laufe die Armband-Scheme auf dem Armband-Simulator aus. Beide Apps müssen vorher installiert sein. isWatchAppInstalled Apple stellt fest, dass der Simulator diese Funktion nicht unterstützt. transferUserInfoBestätige also diese Einstellung auf echtem Hardware.

Für Geräte stecke das iPhone ein, stelle sicher, dass das Armband den Entwicklermodus aktiviert hat, und wähle das Armband als Ausführungsziel für die Armband-Scheme aus. Verwende getInfo() als deine Rauchprobe:

getInfo() ergebnis Bedeutung
isPaired: false Kein Armband gepaart mit diesem Telefon
isWatchAppInstalled: false Armband-App fehlt oder Bundle-ID/ Begleit-Einstellung falsch
isReachable: falsetrue, rest wahr Watch app nicht im Vordergrund oder außer Reichweite
activationState: 2alle wahr Vorbereitet für sendMessage

Troubleshooting

isWatchAppInstalled bleibt falsch. Überprüfen Sie die ID des Watch-Bundles, überprüfen Sie, ob das Watch-Target im App Ziel (Build Phasen > Watch-Inhalt einbetten), und beide Apps neu installieren.

Die Nachrichten vom Watch erreichen das JavaScript nie. Hören Sie auf die Listener an, bevor der Uhrschalter sendet, und bestätigen Sie, dass die Uhr anruft. WatchConnector.shared.activate() Beim Start. Überprüfe auf dem Telefon die Xcode-Konsole für die Aktivitätsprotokolle des Plugins.

sendMessage ablehnt mit „Watch ist nicht erreichbar“. Wenn die Uhranwendung geschlossen wird. Fällt zurück auf updateApplicationContext.

replyToMessage erscheint ignoriert. Passen Sie den genauen callbackId aus dem Ereignis und antworten Sie schnell. Der Antwort-Handler der Uhr hat eine Zeitüberschreitung.

Der Build scheitert mit „Der Bundle-Bezeichner des eingebetteten Binärs ist nicht vorangestellt“. Die Apple Watch Bundle ID muss mit der iOS Bundle ID beginnen.

Archiv-Upload abgelehnt wegen fehlender Icons. Die Uhr-Targets benötigen ihre eigenen App-Icons in Assets.xcassets.

Die Versendung der Uhranwendung

Die Uhranwendung ist kein separates Produkt. Sie ist in das iOS-Archiv eingebettet, gemeinsam hochgeladen und auf derselben App Store Connect-Registerkarte angezeigt, wo Sie unter der Uhr-Taste Apple Watch-Screenshots hinzufügen. Was immer Ihr Archiv produziert, lokale Xcode, CI oder Capgo Build, benötigt eine Bereitstellungsprofil für beide Bundle-IDs und muss Xcode 26 verwenden.

Denken Sie daran, dass Updates wichtig sind. Capgo live Updates Kann Änderungen an das Telefon-Bundle senden, ohne dass eine App-Store-Überprüfung erforderlich ist, was nützlich ist, wenn die TypeScript-Seite Ihres Watch-Bridge einen Fehler hat. Swift code auf dem Watch, und jede Änderung an dem nativen Plugin, geht immer noch durch den App Store. Versionieren Sie die Nachrichtenformat, zum Beispiel mit einem v Ein Schlüssel in jedem Dictionary, so dass ein neuerer Telefon-Bundle weiterhin mit einem älteren Uhr- Build funktioniert.

Wrap-up

Die Trennung ist einfach, wenn man sie akzeptiert: SwiftUI für die Uhr, Capacitor für alles andere und drei WatchConnectivity-Kanäle dazwischen. Installieren @capgo/capacitor-watchFügen Sie den Watch-Target mit CapgoWatchSDK hinzu, halten Sie die Payloads klein und testen Sie auf gepaarter Hardware, bevor Sie einreichen.

Live-Updates für Capacitor-Apps

Wenn ein Web-Schicht-Bug live ist, schicken Sie die Reparatur über Capgo anstatt Tage zu warten, bis die App-Store-Zulassung vorliegt. Die Benutzer erhalten die Aktualisierung im Hintergrund, während native Änderungen im normalen Review-Verfahren bleiben.

menschliche Unterstützung von Martin

Jetzt loslegen

Neueste von unserem Blog

Capgo gibt Ihnen die besten Einblicke, die Sie benötigen, um eine wirklich professionelle mobile App zu erstellen.