Saltar al contenido principal
Tutoriales iOS Capacitor

Cómo crear una aplicación de Apple Watch para una aplicación Capacitor

Crear una aplicación de Apple Watch para tu aplicación Capacitor: agrega un objetivo watchOS, escribe el lado SwiftUI y sincroniza los datos con el iPhone utilizando @capgo/capacitor-watch.

Créditos del artículo

Martín Donadieu

Escritor

Valeria

Revisor

Jordan

Editor

Cómo crear una aplicación de Apple Watch para una aplicación Capacitor

Para crear una aplicación de Apple Watch para una aplicación Capacitor, agregue un objetivo nativo watchOS a su proyecto iOS, escriba la interfaz de usuario en SwiftUI y conecte a su web code con el @capgo/capacitor-watch plugin, que envuelve el marco de trabajo WatchConnectivity de Apple. La aplicación de teléfono mantiene su capa web Capacitor, y la aplicación de reloj se convierte en un pequeño compañero nativo que envía y recibe diccionarios.

This guide covers the full path on Capacitor 8 and Xcode 26: the architecture, the Xcode target, the Swift and TypeScript code on each side, which transfer method to use, testing on simulators and devices, and how the watch app ships.

¿Por qué la interfaz de la reloj es nativa y el teléfono permanece en Capacitor

watchOS no envía una WebView. No hay WKWebView en la reloj, por lo que una aplicación Capacitor no puede ejecutarse allí, y ningún plugin cambia eso. Lo que puede hacer es dividir las responsabilidades:

Nivel Ejecuta en Idioma Job
Capacitor app iPhone TypeScript, tu marco de trabajo de elección TypeScript, tu marco de elección
@capgo/capacitor-watch iPhone Swift (plugin), JS API Swift (plugin), JS __CAPGO_KEEP_0__
CapgoWatchSDK Apple Watch Swift Manejo de sesión en la reloj
App de reloj Apple Watch SwiftUI Small screens, glanceable UI, quick actions

En la práctica, la aplicación de reloj es "dependiente": obtiene sus datos del teléfono. Mantenga la lógica en el teléfono donde ya existe en TypeScript, y envíe solo a la reloj lo que necesita mostrar.

Requisitos previos

  • Una Capacitor 8 aplicación con la plataforma iOS agregada. Si aún está en una versión anterior, siga el Capacitor 8 guía de actualización primero.
  • Xcode 26 en un Mac. Apple ha requerido Xcode 26 para subir aplicaciones a la Tienda de MacApp desde abril de 2026, ver el requisito de Xcode 26.
  • Una cuenta de desarrollador de Apple para pruebas y distribución de dispositivos.
  • iOS 15 o posterior en el teléfono (el mínimo del plugin) y watchOS 9 o posterior en el reloj (el SDK mínimo).
  • Idealmente, un iPhone real unido a un reloj Apple real. Los simuladores ayudan, pero no cubren cada tipo de transferencia.

Paso 1: Instale el plugin en el lado del teléfono

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

El plugin se activa WCSession tan pronto como se carga, por lo que no hay llamada de inicialización. Comience leyendo el estado de la conexión:

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

La referencia completa del API se encuentra en los plugin docs y la página del plugin.

Paso 2: Agregue un objetivo watchOS en Xcode

Abrir el proyecto de iOS con bunx cap open ios.Capacitor 8 proyectos creados con Swift Package Manager abierto App.xcodeproj; proyectos de CocoaPods más antiguos abiertos App.xcworkspaceFunciona cualquiera.

  1. Elegir Archivo > Nuevo > Objetivo, seleccionar la watchOS seleccionar App.
  2. Nómbralo, por ejemplo MyWatch, y utilízalo SwiftUI como la interfaz.
  3. Asegúrese de que la aplicación de reloj esté integrada en su proyecto existente App como su compañero. Esa configuración es lo que hace que Xcode incruste la aplicación de reloj en la compilación de iPhone y establezca el identificador de paquete de compañero.
  4. Deje las escenas de notificaciones y las complicaciones fuera a menos que las necesite ahora. Puede agregar widgets más tarde.
  5. Aceptar la solicitud para activar el nuevo esquema.

La regla del identificador de paquete

El ID de la aplicación de reloj debe comenzar con el ID de la aplicación de iPhone. Si su aplicación es com.example.shop, Xcode propone com.example.shop.watchkitapp. Mantenga ese prefijo. Si cambia el identificador de paquete de iOS más tarde, cambie el de la reloj también, o la compilación fallará la validación y WatchConnectivity no unirá las dos aplicaciones.

Bajo Configuración y firmasCon la firma automática, Xcode registra el segundo ID de aplicación y el perfil de configuración de forma automática para usted.

Agregar CapgoWatchSDK a la meta de reloj

  1. Archivo > Agregar dependencias de paquete.
  2. Entrar https://github.com/Cap-go/capacitor-watch.git.
  3. Usar "Hasta la próxima versión mayor" desde 8.0.0.
  4. Cuando Xcode le pregunte qué productos agregar, seleccione solo CapgoWatchSDK y asígnelo a la reloj target, no la aplicación iOS. El lado iOS ya obtiene el plugin a través cap sync.

Step 3: Escribir la aplicación de reloj en SwiftUI

El SDK expone WatchConnector.sharedan, y ObservableObject con publicado isReachable, isActivated, lastMessagey, y applicationContext Propiedades. Actívalo cuando el app arranque:

import SwiftUI
import CapgoWatchSDK

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

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

Una pequeña pantalla que muestra datos empujados desde el teléfono y envía una acción de vuelta:

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

El async variante de sendMessage envía con un manejador de respuesta, por lo que el teléfono lo recibe como un messageReceivedWithReply evento. La variante basada en callbacks sendMessage(_:replyHandler:errorHandler:) te permite saltar la respuesta.

Si prefieres callbacks de delegados sobre observar propiedades publicadas, conoce a WatchConnectorDelegate y establece WatchConnector.shared.delegatePosee métodos para mensajes, mensajes con un manejador de respuesta, contexto de la aplicación, información del usuario, alcance y activación.

Step 4: Habla con la reloj desde TypeScript

Registra oyentes temprano, por ejemplo, en el arranque de tu aplicación, para que no se pierdan eventos que llegan al lanzamiento.

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

Siempre responde a messageReceivedWithReplyLa reloj está esperando, y una solicitud sin respuesta termina en un error de tiempo de espera en el lado del reloj.

¿Cuál método de transferencia debes usar?

WatchConnectivity te da tres canales, y el plugin mapea cada uno:

Método Entrega Requiere reloj accesible Bueno para
sendMessage Conveniente para Sí, rechaza lo contrario Button taps, live updates while both apps are open
updateApplicationContext El valor más reciente gana, se entrega cuando sea posible No Estado actual: conteos, ajustes, usuario conectado
transferUserInfo Programado, se entrega en orden No Eventos que deben llegar todos: ejercicios registrados, registros creados

Un patrón que funciona bien: utilice el contexto de la aplicación como fuente de verdad para lo que el reloj muestra, utilice sendMessage solamente para interacciones mientras la aplicación del reloj está abierta, y utilice transferUserInfo para cualquier cosa que no pueda permitirse perder.

Limitaciones para diseñar alrededor de

  • Tamaño del paquete. WatchConnectivity rechaza paquetes que son demasiado grandes con payloadTooLargey Apple no publica un conteo de bytes fijo para cada canal. Mantenga los paquetes pequeños: IDs, conteos, cadenas cortas. Recupere contenido grande desde su API en lugar de eso.
  • Tipos de paquetes. Los datos deben ser compatibles con lista de propiedades: cadenas, números, booleanos, fechas, datos, arreglos y diccionarios. null Los valores de JavaScript no son válidos. Elimínelos antes de enviar.
  • El teléfono debe estar ejecutando su aplicación para manejar eventos. Los oyentes viven en el entorno de tiempo de ejecución JavaScript de Capacitor. Si iOS ha terminado la aplicación, los eventos no llegarán a su TypeScript hasta que la aplicación se ejecute de nuevo. El contexto y la información del usuario se quedan en cola por parte del sistema, pero diseñe la interfaz de usuario de la reloj para que funcione con contexto caché.
  • Conexión. Un reloj Apple solo se conecta con un iPhone. Los usuarios de Android no pueden utilizarlo, y la implementación del plugin para Android se enfoca en Wear OS en lugar de eso, cubierto en nuestra Guía de Wear OS.
  • Independencia. A una aplicación de reloj construida con WatchConnectivity le depende el teléfono. Si el reloj debe funcionar lejos del teléfono, agrega una segunda fuente de datos como tu propia API a través de la conexión de red del reloj.

Pruebas en simuladores y dispositivos

Puedes iterar en la disposición de SwiftUI en el simulador de reloj, pero la transferencia de datos requiere una configuración pareja.

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

Ejecuta la aplicación de iOS en el simulador de iPhone pareja, luego ejecuta el esquema de reloj en el simulador de reloj. Ambas aplicaciones deben estar instaladas antes isWatchAppInstalled que se convierta en verdadero. Apple nota que el Simulador no admite transferUserInfo, por lo que confirma ese camino en hardware real.

Para dispositivos, conecta el iPhone, asegúrate de que el reloj tenga el modo de desarrollador habilitado y selecciona el reloj como destino de ejecución para el esquema de reloj. Utiliza getInfo() como tu prueba de humo:

getInfo() resultado Significado
isPaired: false No hay reloj pairado con este teléfono
isWatchAppInstalled: false Aplicación de reloj faltante, o ID de bundle / configuración de compañero incorrecta
isReachable: falseVerdadero Aplicación de reloj no en primer plano o fuera de alcance
activationState: 2Verdadero, todo Preparado para sendMessage

Solución de problemas

isWatchAppInstalled Se mantiene en falso. Verifique la prefija de ID de paquete de reloj, asegúrese de que el objetivo de reloj esté integrado en el App Configure el objetivo (Fases de compilación &gt; Contenido de reloj) y reinstale ambas aplicaciones.

Los mensajes del reloj nunca llegan a JavaScript. Registre los oyentes antes de que el reloj envíe y confirme que el reloj llama a WatchConnector.shared.activate() Al iniciar. En el teléfono, revise el consola de Xcode para el registro de activación del plugin.

sendMessage rechaza con "El reloj no está disponible". Esperado cuando la aplicación del reloj está cerrada. Regresa a updateApplicationContext.

replyToMessage parece ignorado. Transmite el exacto callbackId responde rápidamente desde el evento y el controlador de la reloj tiene un tiempo de espera.

La compilación falla con “El identificador de paquete binario incorporado no está prefijado”. El ID del paquete del reloj debe comenzar con el ID de paquete de iOS.

La subida a archivo archivada rechazada por falta de iconos. Los objetivos de reloj necesitan su propio icono en Assets.xcassets.

Envíe la aplicación del reloj

La aplicación del reloj no es un producto separado. Está incorporada en el archivo de iOS, se sube juntos y se muestra en el mismo registro de App Store Connect, donde agregas capturas de pantalla de Apple Watch en la pestaña de reloj. Lo que produce tu archivo, Xcode local, CI o Capgo Compilación, requiere un perfil de provisión para ambos IDs de paquete y debe utilizar Xcode 26.

Ten en cuenta una cosa para las actualizaciones. Capgo actualizaciones en vivo pueden enviar cambios al paquete web del teléfono sin una revisión de la tienda, lo cual es útil cuando el lado de TypeScript de su puente de reloj tiene un error. Swift code en el reloj, y cualquier cambio al plugin nativo, todavía pasa por la Tienda de Mac App. Versione su formato de mensaje, por ejemplo con un v campo en cada diccionario, por lo que un paquete de teléfono más nuevo sigue funcionando con una versión de reloj más antigua.

Resumen

La división es simple una vez que la aceptes: SwiftUI para la muñeca, Capacitor para todo lo demás, y tres canales de WatchConnectivity entre medias. Instale @capgo/capacitor-watchagregue el objetivo de reloj con CapgoWatchSDK, mantenga los payloads pequeños, y pruebe en hardware pairado antes de enviar.

Actualizaciones en vivo para aplicaciones Capacitor

Cuando un error en la capa web está vivo, envía la corrección a través de Capgo en lugar de esperar días a la aprobación de la tienda de aplicaciones. Los usuarios obtienen la actualización en segundo plano mientras los cambios nativos siguen en el camino de revisión normal.

Últimas noticias de nuestro Blog

Capgo te brinda las mejores herramientas para crear una aplicación móvil profesional de verdad.