Saltar al contenido

Primeros pasos

GitHub

Puedes usar nuestro setup asistido por IA para instalar el plugin. Añade las skills de Capgo a tu herramienta de IA con el siguiente comando:

Ventana de terminal
bunx skills add https://github.com/Cap-go/capgo-skills --skill capacitor-plugins

Luego usa el siguiente prompt:

Use the `capacitor-plugins` skill from `Cap-go/capgo-skills` to install the `@capgo/capacitor-live-activities` plugin in my project.

Si prefieres la configuración manual, instala el plugin ejecutando estos comandos y sigue las instrucciones de cada plataforma:

Ventana de terminal
bun add @capgo/capacitor-live-activities
bunx cap sync

Instalar y sincronizar el plugin no crea la interfaz nativa de Live Activity. ActivityKit requiere un Widget Extension que registre una configuración de Live Activity antes de que startActivity pueda mostrar algo.

  • Usa iOS 16.1 o superior tanto para el target de la app como para el Widget Extension.
  • Prueba en un dispositivo iOS o un simulador compatible. La Dynamic Island solo aparece en modelos compatibles; otros dispositivos usan la presentación en la Lock Screen.
  • Mantén los datos combinados (estáticos y dinámicos) de ActivityKit por debajo del límite de 4 KB de Apple.

Abre el proyecto nativo de iOS:

Ventana de terminal
bunx cap open ios

Luego:

  1. Selecciona Archivo > Nuevo > Target.
  2. Añade una extensión de widget.
  3. Activar Incluir Live Activity.
  4. Desactivar Incluir el Intent de configuración a menos que la app también necesite un widget configurable.
  5. Asegúrate de que la extensión generada esté integrada en el target principal de la app.

La Widget Extension debe contener un ActivityConfiguration y registrarlo en su WidgetBundle. Debe proporcionar cada presentación de Live Activity requerida:

  • Pantalla bloqueada
  • Dynamic Island expandida
  • Dynamic Island compacta (leading y trailing)
  • Dynamic Island mínima

Añadir solo el target no es suficiente. La app nativa o el plugin deben llamar a las APIs request, update y end de ActivityKit. La extensión debe contener code de SwiftUI que puedan decodificar y renderizar el mismo ActivityAttributes y el estado de contenido usados en esas llamadas. Incluye modelos de ActivityKit compartidos tanto en el target de la app principal como en el de la Widget Extension. La plantilla de Live Activity generada por Xcode no renderiza automáticamente los layouts JSON pasados a este plugin; la extensión también necesita un renderer de layout nativo compatible.

Añade la siguiente clave al target principal de la app Info.plist:

<key>NSSupportsLiveActivities</key>
<true/>

Si el proyecto genera su Info.plist, añade Compatible con Live Activities con un valor booleano de YES en las propiedades del target personalizado de iOS de la app principal.

3. Configurar el App Group para imágenes compartidas

Sección titulada “3. Configurar el App Group para imágenes compartidas”

Solo necesitas un App Group cuando usas saveImage, removeImage, listImages, o cleanupImages. El plugin deriva el identificador del App Group del bundle identifier de la app principal usando este formato exacto:

group.<MAIN_APP_BUNDLE_ID>.liveactivities

Por ejemplo, una app con bundle identifier com.example.delivery debe usar:

group.com.example.delivery.liveactivities

En Xcode, añade la capability de App Groups tanto al target de la app principal como al target de la Widget Extension; luego, habilita el mismo identificador en ambos targets.

Las extensiones de Live Activity no pueden acceder a la red. Descarga las imágenes remotas en la app principal y guárdalas en el App Group compartido antes de usarlas en una Live Activity. Para imágenes locales, habilita también la Widget Extension en la target membership de los assets.

Al usar behavior.widgetUrl o una secuencia de temporizadores tapUrl, registra el URL scheme o Universal Link correspondiente en la app principal. Para un scheme personalizado como myapp://order/12345, añade el scheme en la sección Info > Tipos de URL de configuración.

Las notificaciones push no son necesarias para las actualizaciones locales iniciadas por la app. Para iniciar, actualizar o finalizar Live Activities desde un servidor:

  • Añade la Notificaciones push capability al target de la app principal.
  • Obtén los tokens de push de ActivityKit y envíalos al servidor.
  • Envía notificaciones de ActivityKit a través de APNs usando el liveactivity tipo push.
  • Añadir NSSupportsLiveActivitiesFrequentUpdates a la app principal Info.plist solo cuando el caso de uso requiera actualizaciones push frecuentes.

Los tokens de push de ActivityKit son distintos a los tokens de dispositivo para notificaciones estándar. Activar solo la capacidad de Push Notifications no es suficiente; las actualizaciones gestionadas por el servidor requieren el manejo de tokens nativos y un backend de APNs.

Checklist de configuración nativa

Sección titulada “Native Setup Checklist”

Antes de llamar a startActivity, verifica que:

  • NSSupportsLiveActivities esté habilitado en el target de la app principal.
  • La Widget Extension está integrada y registra un ActivityConfiguration.
  • La implementación nativa de ActivityKit y la Widget Extension usan el mismo ActivityAttributes tipo.
  • Los deployment targets de la app y de la Widget Extension son iOS 16.1 o posterior.
  • Las Live Activities están habilitadas para la app en los Ajustes de iOS.
  • El App Group correspondiente está habilitado en ambos targets al usar imágenes compartidas.
  • Cualquier custom URL scheme utilizado por widgetUrl o tapUrl está registrado.
import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { supported, reason } = await CapgoLiveActivities.areActivitiesSupported();
if (supported) {
console.log('Live Activities are supported!');
} else {
console.log('Not supported:', reason);
}
import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { activityId } = await CapgoLiveActivities.startActivity({
layout: {
type: 'container',
direction: 'horizontal',
children: [
{ type: 'text', content: 'Order #{{orderNumber}}', fontSize: 16, fontWeight: 'bold' },
{ type: 'text', content: '{{status}}', fontSize: 14, color: '#666666' }
]
},
dynamicIslandLayout: {
expanded: {
leading: { type: 'image', source: 'sfSymbol', value: 'box.truck' },
trailing: { type: 'text', content: '{{eta}}' },
center: { type: 'text', content: '{{status}}' },
bottom: { type: 'progress', value: 'progress' }
},
compactLeading: { type: 'image', source: 'sfSymbol', value: 'box.truck' },
compactTrailing: { type: 'text', content: '{{eta}}' },
minimal: { type: 'image', source: 'sfSymbol', value: 'box.truck' }
},
data: {
orderNumber: '12345',
status: 'On the way',
eta: '10 min',
progress: 0.6
}
});
console.log('Started activity:', activityId);
import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.updateActivity({
activityId: 'abc123',
data: {
status: 'Arrived!',
eta: 'Now',
progress: 1.0
},
alertConfiguration: {
title: 'Delivery Update',
body: 'Your order has arrived!'
}
});
  • Listeners: elimina los handles cuando se desmonten las pantallas.
  • Sync nativo: ejecuta bunx cap sync tras actualizar los plugins.
  • Fuente de verdad: confianza src/definitions.ts en el repo de GitHub.

Comprueba si este dispositivo es compatible con Live Activities. Requiere iOS 16.1+ y que el dispositivo sea compatible.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { supported, reason } = await CapgoLiveActivities.areActivitiesSupported();
if (supported) {
console.log('Live Activities are supported!');
} else {
console.log('Not supported:', reason);
}

Inicia una nueva Live Activity con el layout y los datos especificados.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { activityId } = await CapgoLiveActivities.startActivity({
layout: {
type: 'container',
direction: 'horizontal',
children: [
{ type: 'text', content: 'Order #{{orderNumber}}', fontSize: 16, fontWeight: 'bold' },
{ type: 'text', content: '{{status}}', fontSize: 14, color: '#666666' }
]
},
dynamicIslandLayout: {
expanded: {
leading: { type: 'image', source: 'sfSymbol', value: 'box.truck' },
trailing: { type: 'text', content: '{{eta}}' },
center: { type: 'text', content: '{{status}}' },
bottom: { type: 'progress', value: 'progress' }
},
compactLeading: { type: 'image', source: 'sfSymbol', value: 'box.truck' },
compactTrailing: { type: 'text', content: '{{eta}}' },
minimal: { type: 'image', source: 'sfSymbol', value: 'box.truck' }
},
data: {
orderNumber: '12345',
status: 'On the way',
eta: '10 min',
progress: 0.6
}
});
console.log('Started activity:', activityId);

Actualiza una Live Activity existente con nuevos datos.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.updateActivity({
activityId: 'abc123',
data: {
status: 'Arrived!',
eta: 'Now',
progress: 1.0
},
alertConfiguration: {
title: 'Delivery Update',
body: 'Your order has arrived!'
}
});

Finaliza una Live Activity.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.endActivity({
activityId: 'abc123',
data: { status: 'Delivered' },
dismissalPolicy: 'after',
dismissAfter: Date.now() + 3600000 // 1 hour from now
});

Obtén todas las Live Activities activas actualmente.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { activities } = await CapgoLiveActivities.getAllActivities();
activities.forEach(activity => {
console.log(`Activity ${activity.activityId}: ${activity.state}`);
});

Guarda una imagen en el contenedor compartido del App Group para usarla en Live Activities. Las imágenes deben guardarse en el contenedor compartido para que la extensión del widget pueda acceder a ellas.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { success, imageName } = await CapgoLiveActivities.saveImage({
imageData: 'base64EncodedImageData...',
name: 'product-image',
compressionQuality: 0.8
});
// Use in layout with: { type: 'image', source: 'saved', value: imageName }

Elimina una imagen guardada del contenedor compartido.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { success } = await CapgoLiveActivities.removeImage({ name: 'product-image' });

Lista todas las imágenes guardadas en el contenedor compartido.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { images } = await CapgoLiveActivities.listImages();
console.log('Saved images:', images);

Elimina todas las imágenes guardadas del contenedor compartido.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.cleanupImages();

Inicia una secuencia de temporizador para entrenamientos o deportes. En iOS: Se muestra en Live Activity y Dynamic Island En Android: Se muestra como una notificación en primer plano con el temporizador

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const { sequenceId } = await CapgoLiveActivities.startTimerSequence({
title: 'HIIT Workout',
steps: [
{ duration: 30, title: 'Jumping Jacks', subtitle: 'Warm up', color: '#FF6B00', icon: 'figure.jumprope' },
{ duration: 10, title: 'Rest', color: '#00C853', icon: 'pause.circle' },
{ duration: 45, title: 'Burpees', subtitle: 'High intensity', color: '#FF0000', icon: 'flame.fill' },
{ duration: 15, title: 'Rest', color: '#00C853', icon: 'pause.circle' },
{ duration: 45, title: 'Mountain Climbers', color: '#FF0000', icon: 'figure.run' },
{ duration: 15, title: 'Rest', color: '#00C853', icon: 'pause.circle' },
],
loop: true,
loopCount: 3,
soundEnabled: true,
vibrateEnabled: true,
countdownBeeps: true,
tapUrl: 'myapp://workout/hiit'
});

Pausa la secuencia del temporizador.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.pauseTimerSequence({ sequenceId: 'abc123' });

Reanuda una secuencia de temporizador pausada.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.resumeTimerSequence({ sequenceId: 'abc123' });

Detiene y descarta la secuencia del temporizador.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.stopTimerSequence({ sequenceId: 'abc123' });

Salta al siguiente paso de la secuencia.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.skipTimerStep({ sequenceId: 'abc123' });

Vuelve al paso anterior de la secuencia.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
await CapgoLiveActivities.previousTimerStep({ sequenceId: 'abc123' });

Obtén el estado actual de una secuencia de temporizador.

import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const state = await CapgoLiveActivities.getTimerState({ sequenceId: 'abc123' });
console.log(`Step ${state.currentStepIndex + 1}/${state.totalSteps}: ${state.currentStep.title}`);
console.log(`Time remaining: ${state.remainingSeconds}s`);

Resultado de comprobar si se admiten las actividades.

export interface AreActivitiesSupportedResult {
/** Whether Live Activities are supported on this device */
supported: boolean;
/** Reason if not supported */
reason?: string;
}

Opciones para iniciar una Live Activity.

export interface StartActivityOptions {
/** Main activity layout (lock screen widget) */
layout: ActivityLayout;
/** Dynamic Island layout configuration */
dynamicIslandLayout: DynamicIslandLayout;
/** Activity behavior settings */
behavior?: LiveActivitiesBehavior;
/** Dynamic data for the activity */
data: Record<string, unknown>;
/** Stale date timestamp (activity becomes stale after this) */
staleDate?: number;
/** Relevance score for activity ordering (0-100) */
relevanceScore?: number;
}

Resultado de iniciar una actividad.

export interface StartActivityResult {
/** Unique activity identifier */
activityId: string;
}

Opciones para actualizar una Live Activity.

export interface UpdateActivityOptions {
/** Activity ID to update */
activityId: string;
/** Updated data */
data: Record<string, unknown>;
/** Optional alert to show with update */
alertConfiguration?: ActivityAlertConfiguration;
/** Updated stale date */
staleDate?: number;
/** Updated relevance score */
relevanceScore?: number;
}

Opciones para finalizar una Live Activity.

export interface EndActivityOptions {
/** Activity ID to end */
activityId: string;
/** Final data to display */
data?: Record<string, unknown>;
/** Dismissal policy */
dismissalPolicy?: 'immediate' | 'default' | 'after';
/** Dismiss after timestamp (when dismissalPolicy is 'after') */
dismissAfter?: number;
}

Resultado de getAllActivities.

export interface GetAllActivitiesResult {
/** List of activities */
activities: ActivityInfo[];
}

Opciones para guardar una imagen.

export interface SaveImageOptions {
/** Base64 encoded image data */
imageData: string;
/** Name to save the image as */
name: string;
/** JPEG compression quality (0-1, default 0.8) */
compressionQuality?: number;
}

Resultado de guardar una imagen.

export interface SaveImageResult {
/** Whether the save was successful */
success: boolean;
/** Saved image name */
imageName: string;
}

Opciones para eliminar una imagen.

export interface RemoveImageOptions {
/** Name of the image to remove */
name: string;
}

Resultado de eliminar una imagen.

export interface RemoveImageResult {
/** Whether the removal was successful */
success: boolean;
}

Resultado de listar las imágenes.

export interface ListImagesResult {
/** List of saved image names */
images: string[];
}

Opciones para iniciar una secuencia de temporizador.

export interface TimerSequenceOptions {
/** Array of steps in the sequence */
steps: TimerStep[];
/** Overall title for the sequence (e.g., "HIIT Workout", "Tabata") */
title?: string;
/** Whether to loop the sequence when complete */
loop?: boolean;
/** Number of times to loop (if loop is true, 0 means infinite) */
loopCount?: number;
/** Play sound on step change (default: true) */
soundEnabled?: boolean;
/** Vibrate on step change (default: true) */
vibrateEnabled?: boolean;
/** Play countdown beeps in last 3 seconds (default: true) */
countdownBeeps?: boolean;
/** Deep link URL when tapping the notification/activity */
tapUrl?: string;
/** Keep screen on during timer (Android only, default: false) */
keepScreenOn?: boolean;
}

Esta página se genera a partir del plugin src/definitions.ts. Vuelve a ejecutar el sync cuando el API público cambie en upstream.

Si estás usando Primeros pasos para planificar las operaciones del dashboard y de API, conéctalo con Uso de @capgo/capacitor-live-activities para la capacidad nativa en Uso de @capgo/capacitor-live-activities, Resumen de API para los detalles de implementación en API Overview, Introducción para los detalles de implementación en la Introducción, Claves de API para los detalles de implementación en las claves de API, y Dispositivos para el detalle de implementación en Devices.