Para usar Apple Intelligence en una app de Capacitor, instala @capgo/capacitor-llm, llama a setModel({ path: 'Apple Intelligence' }), verifica getReadiness(), luego crea un chat y transmite las respuestas a través del textFromAi evento. Internamente, el plugin utiliza el framework Foundation Models de Apple, introducido con iOS 26, que ejecuta el modelo de lenguaje en el dispositivo de Apple sin clave de API, sin costo por solicitud y sin que los datos salgan del teléfono.
Esta guía cubre lo que ofrece el framework, los requisitos de dispositivo, una integración completa en TypeScript, la ventana de contexto de 4.096 tokens, el manejo de errores, notas para App Review y cómo el mismo code funciona en Android.
Lo que Apple Intelligence ofrece a los desarrolladores de apps
Con iOS 26, Apple abrió su modelo de fundación en el dispositivo a apps de terceros a través del Modelos de base framework. En Swift trabajas con SystemLanguageModel y LanguageModelSession. El plugin encapsula esos modelos para que tu web code pueda usarlos:
| Concepto Foundation Models | Equivalente en el plugin |
|---|---|
SystemLanguageModel.default.availability |
getReadiness() |
LanguageModelSession |
createChat() devuelve un id |
session.streamResponse(to:) |
sendMessage() además de textFromAi eventos |
| Errores durante la generación | generationError evento y una promesa rechazada sendMessage |
El modelo tiene unos 3 mil millones de parámetros. Es bueno resumiendo, reescribiendo, extrayendo, clasificando y generando textos cortos. No sustituye a un modelo grande en la nube para preguntas de conocimiento abierto, y Apple lo dice en su propia guía. Diseña las funciones en torno al texto que el usuario ya tiene.
Requisitos de dispositivo y SO
| Requisito | Detalle |
|---|---|
| iPhone | iPhone 15 Pro, 15 Pro Max y modelos iPhone 16 o posteriores |
| iPad | iPad mini (A17 Pro), iPads con M1 o posterior |
| Mac | Macs con Apple silicon (relevante para pruebas en el Simulator) |
| SO | iOS 26 / iPadOS 26 o posterior |
| Configuración | Apple Intelligence activado en Ajustes > Apple Intelligence & Siri |
| Idioma | Idioma del dispositivo y Siri configurado en un idioma compatible con Apple Intelligence |
| Almacenamiento | Apple lista unos 7 GB de espacio libre para los modelos de Apple Intelligence |
| Toolchain | Xcode 26, que App Store Connect también exige para uploads desde abril de 2026 |
Si tu proyecto aún compila con una versión anterior de Xcode, consulta Requisito de Xcode 26 de Apple para apps de Capacitor. El objetivo de despliegue mínimo de tu app no necesita cambiar. El plugin soporta iOS 15 y posteriores, y solo interactúa con Foundation Models en iOS 26.
Instalar el plugin
bun add @capgo/capacitor-llm
bunx cap sync ios
Usa el plugin 8.x con Capacitor 8. No se necesitan claves en Info.plist ni entitlements para Apple Intelligence. Si aún estás en Capacitor 7, el guía de actualización de Capacitor 8 viene primero. Documentación de referencia: /docs/plugins/llm/.
Paso 1: Selecciona el modelo y verifica la disponibilidad
setModel({ path: 'Apple Intelligence' }) selecciona el modelo del sistema y resuelve de inmediato. La disponibilidad real proviene de getReadiness(), que mapea el enum de disponibilidad de Apple a cadenas legibles:
readiness valor |
Significado | Qué mostrar |
|---|---|---|
ready |
Modelo disponible | La función |
Device is not eligible for Apple Intelligence |
Hardware no compatible | Ocultar la función o usar un fallback en la nube |
Apple Intelligence is not enabled |
El usuario la desactivó | Una pista para activarla en Ajustes |
Model is not ready |
El modelo aún se está descargando o preparando | «Preparando», reintenta más tarde |
Apple Intelligence requires iOS 26.0 or later |
iOS antiguos | Ocultar la función |
import { Capacitor } from '@capacitor/core';
import { CapgoLLM } from '@capgo/capacitor-llm';
export type AIState = 'ready' | 'enable-in-settings' | 'preparing' | 'unsupported';
export async function initAppleIntelligence(): Promise<AIState> {
if (Capacitor.getPlatform() !== 'ios') return 'unsupported';
await CapgoLLM.setModel({ path: 'Apple Intelligence' });
const { readiness } = await CapgoLLM.getReadiness();
if (readiness === 'ready') return 'ready';
if (readiness.includes('not enabled')) return 'enable-in-settings';
if (readiness.includes('not ready')) return 'preparing';
return 'unsupported';
}
Comprueba de nuevo cuando la app vuelva al primer plano. Los usuarios suelen activar Apple Intelligence después de ver tu indicación, y la descarga del modelo puede completarse mientras tu app está en segundo plano.
import { App } from '@capacitor/app';
App.addListener('appStateChange', async ({ isActive }) => {
if (isActive) updateAIState(await initAppleIntelligence());
});
Paso 2: Crea un chat con instrucciones
Un chat se corresponde con un LanguageModelSession, que conserva el historial de la conversación. El createChat() no acepta opciones, así que coloca tus instrucciones al inicio del primer mensaje:
const INSTRUCTIONS =
'You summarize meeting notes. Reply with at most 5 bullet points. ' +
'Keep names and dates exactly as written. Do not add information.';
const { id: chatId } = await CapgoLLM.createChat();
Usa un chat por tarea. Un chat que sigue creciendo acabará alcanzando el límite de contexto descrito a continuación.
Paso 3: Transmite la respuesta a la UI
En iOS, cada textFromAi el evento incluye una instantánea de la respuesta hasta el momento, porque así es como Foundation Models transmite en streaming. En Android con Gemini Nano, los eventos solo llevan el nuevo texto. Este helper maneja ambos casos y se resuelve con el texto final:
import { CapgoLLM } from '@capgo/capacitor-llm';
function mergeChunk(current: string, chunk: string) {
return chunk.startsWith(current) ? chunk : current + chunk;
}
export async function ask(chatId: string, message: string, onText: (t: string) => void) {
let text = '';
let finish!: (value: string) => void;
let fail!: (error: Error) => void;
const done = new Promise<string>((resolve, reject) => {
finish = resolve;
fail = reject;
});
const handles = await Promise.all([
CapgoLLM.addListener('textFromAi', (e) => {
if (e.chatId !== chatId) return;
text = mergeChunk(text, e.text);
onText(text);
}),
CapgoLLM.addListener('aiFinished', (e) => {
if (e.chatId === chatId) finish(text);
}),
CapgoLLM.addListener('generationError', (e) => {
if (!e.chatId || e.chatId === chatId) fail(new Error(e.error));
}),
]);
try {
await CapgoLLM.sendMessage({ chatId, message });
return await done;
} finally {
await Promise.all(handles.map((h) => h.remove()));
}
}
Poniéndolo todo junto: resumir notas en el dispositivo
export async function summarizeNotes(notes: string, render: (t: string) => void) {
const state = await initAppleIntelligence();
if (state !== 'ready') throw new Error(`AI unavailable: ${state}`);
const { id } = await CapgoLLM.createChat();
const prompt = `${INSTRUCTIONS}\n\nNotes:\n${notes.slice(0, 8000)}\n\nSummary:`;
return ask(id, prompt, render);
}
El slice es una salvaguarda básica contra entradas enormes. Un mejor enfoque es resumir documentos largos por fragmentos y luego resumir los resúmenes, cada uno en un chat nuevo.
En un componente de framework, deshabilita el botón mientras ask se ejecuta. El plugin rechaza un segundo sendMessage en el mismo chat con “chat is responding, please wait before asking new questions”.
La ventana de contexto de 4.096 tokens
El modelo en el dispositivo tiene una ventana de contexto de 4.096 tokens. Todo cuenta para ella: instrucciones, cada turno anterior en el chat, el nuevo prompt y la respuesta que se está generando. Cuando una sesión la excede, Foundation Models lanza un error “exceeded context window size”, que llega a ti como un generationError evento y una promesa rechazada sendMessage.
Reglas prácticas:
- Un chat por tarea, no un chat por pantalla.
- Mantén las instrucciones cortas y específicas.
- En chats de varios turnos, inicia uno nuevo cuando se alargue y pasa un resumen breve de la conversación anterior.
- Pide una salida concisa. Las respuestas largas consumen el mismo presupuesto.
Ajuste de la salida
En la ruta de Apple Intelligence, el plugin usa la configuración de generación predeterminada del sistema. temperature, topk, y maxTokens en setModel aplican a las rutas personalizadas de LiteRT-LM y MediaPipe. Para guiar el modelo de Apple, confía en el prompt: indica la longitud de la respuesta, el formato (viñetas, JSON, una frase) e incluye un ejemplo corto si el formato es importante.
El mismo code en Android
Solo cambia la selección del modelo:
const path = Capacitor.getPlatform() === 'ios' ? 'Apple Intelligence' : 'Gemini Nano';
await CapgoLLM.setModel({ path });
En Android, setModel rechaza si Gemini Nano no está disponible, y puedes usar un modelo Gemma descargable a través del mismo plugin. Los detalles están en cómo usar Gemini Nano en una app de Capacitor.
Pruebas
- Dispositivo real: la vía fiable. Usa un iPhone compatible con iOS 26 y Apple Intelligence activado.
- Simulador: puede usar el modelo si el Mac anfitrión ejecuta macOS 26 con chip Apple y Apple Intelligence activado. El comportamiento y la velocidad difieren de un teléfono, así que verifica en hardware.
- Estados no compatibles: prueba con Apple Intelligence desactivado para comprobar tu UI de «activar en Ajustes», y en un iPhone o versión de iOS anterior para verificar que la función se oculta correctamente.
Revisión de la app y privacidad
Los prompts y respuestas se quedan en el dispositivo, por lo que la generación on-device no añade recopilación de datos a tu etiqueta de privacidad por sí sola. Dos cosas siguen siendo responsabilidad tuya:
- Apple publica requisitos de uso aceptable para el framework Foundation Models. Léelos antes de publicar, especialmente para funciones que generan contenido mostrado a otros usuarios.
- El modelo tiene guardrails integrados y puede rechazar algunos prompts o salidas. Trata un rechazo como un resultado normal y muestra un mensaje claro.
Como los prompts son cadenas de texto plano en tu web code, puedes mejorarlos después del lanzamiento con actualizaciones Live Update de Capgo en lugar de esperar a un nuevo build de App Store. Los cambios en el code nativo, incluidas las actualizaciones de plugins, siguen requiriendo una publicación en la tienda, que puedes construir en la nube con Build de Capgo.
Errores comunes y soluciones
| Síntoma | Causa probable | Solución |
|---|---|---|
readiness es «El dispositivo no es elegible» |
iPhone anterior al 15 Pro o iPad no compatible | Ocultar la función o usar un modelo en el servidor |
readiness es «no habilitado» |
El usuario desactivó Apple Intelligence | Show a Settings hint, recheck on resume |
readiness es «Model is not ready» |
El modelo sigue descargándose | Mostrar estado de preparación, reintentar más tarde |
sendMessage rechaza «error deviceNotEligible error» |
Enviar sin comprobar la disponibilidad | Condicionar en getReadiness() primero |
| «chat not found» | Chat creado antes de un nuevo setModel llamar |
Llamar a setModel borra los chats, crea uno nuevo |
| “el chat está respondiendo” | Segundo mensaje enviado durante el streaming | Desactivar entrada hasta aiFinished |
generationError mencionando la ventana de contexto |
Chat demasiado largo | Iniciar nuevo chat con un resumen |
| Error de build sobre Foundation Models | Xcode anterior a la versión 26 | Actualiza Xcode o haz el build en la nube |
Resumen
Apple Intelligence ofrece un modelo de lenguaje gratuito, privado y offline a cada iPhone compatible con iOS 26, y una app Capacitor puede usarlo con pocas líneas de TypeScript. Selecciona el modelo, condiciona la UI getReadiness(), mantén cada tarea en su propio chat corto, haz streaming de snapshots a la UI y gestiona los rechazos y errores de contexto como resultados normales. Para una visión más amplia sobre cómo implementar funciones de IA en apps híbridas, lee por qué Capacitor funciona bien para apps móviles con IA.