Saltar al contenido principal

Cómo usar Gemini Nano en una app Capacitor

Usa Gemini Nano en una app de Capacitor para IA en el dispositivo en Android: soporte de dispositivos, comprobaciones de AICore, streaming con @capgo/capacitor-llm y un fallback de Gemma.

Ilustración de funciones de IA ejecutándose dentro de una app móvil Capacitor

Para usar Gemini Nano en una app Capacitor, instala @capgo/capacitor-llm, llama a setModel({ path: 'Gemini Nano' }) en Android, luego crea un chat y transmite la respuesta a través del textFromAi evento. El plugin se comunica con Gemini Nano a través de la API de ML Kit GenAI Prompt de Google, que ejecuta el modelo dentro del servicio del sistema AICore de Android, así que el texto nunca sale del teléfono.

Esta guía cubre cómo funciona Gemini Nano, qué dispositivos lo admiten, las llamadas exactas al plugin, streaming, cuotas y límites, un fallback con Gemma para teléfonos no compatibles y cómo el mismo code llega a Apple Intelligence en iOS.

Cómo funciona Gemini Nano en Android

Gemini Nano es el modelo Gemini más pequeño de Google, diseñado para teléfonos. Las apps no lo incluyen en el bundle. El AICore el servicio lo descarga, lo actualiza y ejecuta la inferencia, y las apps acceden a él a través de APIs de ML Kit GenAI:

  • Prompt API: prompts de texto libre, el API que utiliza este plugin (com.google.mlkit:genai-prompt).
  • APIs de funciones: tareas fijas como resumen, corrección de textos, reescritura y descripción de imágenes.

Google publica el Prompt API como beta, sin SLA ni política de deprecación, así que espera cambios de comportamiento entre versiones y mantén la integración detrás de tu propio wrapper pequeño.

Al ser inferencia local, obtienes tres cosas que un modelo en la nube no te da: funciona offline, no tiene coste por token y el texto del usuario se queda en el dispositivo. La contrapartida es un modelo más pequeño, con contexto y salida cortos, así que elige tareas que encajen: reescribir, resumir una nota, clasificar un mensaje, extraer campos o redactar respuestas cortas.

Dispositivos compatibles y requisitos

Google publica la lista de dispositivos compatibles por API en el sitio de ML Kit GenAI, agrupada por versión de Gemini Nano (nano-v2, nano-v3, nano-v4). Para el Prompt API cubre el Pixel 9 y posteriores, flagships recientes de Samsung Galaxy S y Z, y flagships recientes de OnePlus, OPPO, Xiaomi, vivo, Honor, realme, Motorola y otros. Consulta la lista actualizada antes de prometer una funcionalidad a un dispositivo concreto.

Cada dispositivo compatible también necesita:

Requisito Detalle
Versión de Android API nivel 26 o superior (el plugin lo verifica)
Bootloader Bloqueado. Google no admite las APIs de GenAI con el bootloader desbloqueado
AICore Presente y configurado. Justo después de configurar o restablecer un dispositivo, puede tardar un poco en completarse
Estado de la app Tu app debe estar en primer plano durante la inferencia

Diferentes versiones de Nano pueden devolver salidas distintas para el mismo prompt. Prueba tus prompts en al menos un dispositivo por cada versión que te interese.

Instalar el plugin

bun add @capgo/capacitor-llm
bunx cap sync

El plugin sigue la versión mayor de Capacitor: usa 8.x con Capacitor 8. No se necesitan cambios en el manifiesto de Android para Gemini Nano. Referencia completa: docs del plugin y página del plugin.

Paso 1: Cargar Gemini Nano y verificar el estado de preparación

setModel con la ruta especial 'Gemini Nano' solicita a ML Kit el estado del modelo. Se resuelve cuando el estado está disponible y se rechaza en caso contrario, con un mensaje que incluye el estado:

Estado de AICore Comportamiento del plugin
disponible setModel resuelve, readinessChange emite ready
descargable Rechaza: “Gemini Nano es descargable pero no se ha descargado en este dispositivo”
descargando Rechaza con el estado «descargando»
no disponible Rechaza: “Gemini Nano no está disponible en este dispositivo”
import { Capacitor } from '@capacitor/core';
import { CapgoLLM } from '@capgo/capacitor-llm';

export async function loadGeminiNano(): Promise<boolean> {
  if (Capacitor.getPlatform() !== 'android') return false;

  try {
    await CapgoLLM.setModel({
      path: 'Gemini Nano',
      temperature: 0.3,
      topk: 16,
    });
  } catch (error) {
    console.warn('Gemini Nano not ready:', error);
    return false;
  }

  const { readiness } = await CapgoLLM.getReadiness();
  return readiness === 'ready';
}

El plugin no inicia por sí solo la descarga del modelo AICore. Si un dispositivo indica que es descargable, el modelo suele llegar después de que otra app o el sistema lo soliciten, así que vuelve a comprobarlo en un arranque posterior en lugar de ocultar la función permanentemente.

Paso 2: Crea un chat y transmite la respuesta

Un chat mantiene el historial de la conversación. En Android, sendMessage se resuelve en cuanto comienza la generación, y el texto llega a través de eventos. Envuélvelo en una promesa que se resuelva en aiFinished:

import { CapgoLLM } from '@capgo/capacitor-llm';

// Android sends deltas. iOS Apple Intelligence sends the full text so far.
// This merge handles both.
function mergeChunk(current: string, chunk: string) {
  return chunk.startsWith(current) ? chunk : current + chunk;
}

export async function ask(
  chatId: string,
  message: string,
  onText: (textSoFar: string) => void,
): Promise<string> {
  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', (event) => {
      if (event.chatId !== chatId) return;
      text = mergeChunk(text, event.text);
      onText(text);
    }),
    CapgoLLM.addListener('aiFinished', (event) => {
      if (event.chatId === chatId) finish(text);
    }),
    CapgoLLM.addListener('generationError', (event) => {
      if (!event.chatId || event.chatId === chatId) fail(new Error(event.error));
    }),
  ]);

  // If the app is backgrounded mid-answer, neither event may arrive
  const timeout = setTimeout(() => fail(new Error('Generation timed out')), 60_000);

  try {
    await CapgoLLM.sendMessage({ chatId, message });
    return await done;
  } finally {
    clearTimeout(timeout);
    await Promise.all(handles.map((h) => h.remove()));
  }
}

Úsalo para una función real, por ejemplo, redactar una respuesta a una reseña de un cliente:

const INSTRUCTIONS =
  'You write short, polite replies to customer reviews for a small shop. ' +
  'Answer each point, stay under 60 words, never promise refunds.';

export async function draftReply(review: string, render: (t: string) => void) {
  const { id } = await CapgoLLM.createChat();
  return ask(id, `${INSTRUCTIONS}\n\nReview:\n${review}\n\nReply:`, render);
}

createChat() no acepta opciones, así que coloca las instrucciones al inicio del primer mensaje. Crea un chat nuevo por tarea. En la ruta de Gemini Nano, el plugin mantiene el historial en memoria y lo envía con cada mensaje, por lo que los chats largos agotan rápidamente el presupuesto de entrada.

Límites para tener en cuenta al diseñar

Límite Valor Qué hacer
Entrada Menos de 4.000 tokens por solicitud (Google) Mantén los chats cortos, recorta documentos largos
Resultado El plugin limita las respuestas de Gemini Nano a 256 tokens Pide salidas cortas, divide tareas largas
Primer plano Inferencia solo cuando tu app está en primer plano Nunca lo ejecutes desde tareas en segundo plano
Cuota Cuotas por app, BUSY y errores de cuota de batería Debounce, evita generar en cada pulsación
Concurrencia Una generación por chat Desactiva el botón de enviar durante el streaming
Velocidad Varios segundos por párrafo Siempre stream a la UI

Trata un error de cuota como temporal. Muestra una opción de reintentar en lugar de un diálogo de error.

Fallback: Gemma 4 cuando Gemini Nano no está disponible

La mayoría de los teléfonos Android en uso hoy no tienen Gemini Nano. El mismo plugin puede ejecutar modelos Gemma abiertos a través de LiteRT-LM, así que mantienes un solo API. El modelo es grande, a menudo más de un gigabyte, así que descárgalo solo después de que el usuario acepte, idealmente en Wi-Fi.

import { Preferences } from '@capacitor/preferences';
import { CapgoLLM } from '@capgo/capacitor-llm';

const GEMMA_URL =
  'https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm/resolve/main/gemma-4-E2B-it.litertlm?download=true';

export async function loadGemma(onProgress: (pct: number) => void) {
  const saved = await Preferences.get({ key: 'gemmaPath' });
  if (saved.value) {
    try {
      await CapgoLLM.setModel({ path: saved.value, modelType: 'litertlm', maxTokens: 4096 });
      return;
    } catch {
      // File missing or corrupt, download again
    }
  }

  const sub = await CapgoLLM.addListener('downloadProgress', (e) => onProgress(e.progress));
  try {
    const { path } = await CapgoLLM.downloadModel({
      url: GEMMA_URL,
      filename: 'gemma-4-E2B-it.litertlm',
    });
    await Preferences.set({ key: 'gemmaPath', value: path });
    await CapgoLLM.setModel({ path, modelType: 'litertlm', maxTokens: 4096 });
  } finally {
    await sub.remove();
  }
}

Luego elige el motor al inicio:

export async function initOnDeviceAI(userAcceptedDownload: boolean, onProgress: (p: number) => void) {
  if (await loadGeminiNano()) return 'gemini-nano';
  if (userAcceptedDownload) {
    await loadGemma(onProgress);
    return 'gemma';
  }
  return 'none';
}

Si ninguno es posible, oculta la función o llama a un modelo en la nube. No bloques los flujos principales con IA local.

El mismo code en iOS

En iOS, el plugin utiliza Apple Intelligence a través del framework Foundation Models. Cambia una línea:

await CapgoLLM.setModel({ path: 'Apple Intelligence' });

createChat, sendMessage, y los eventos se mantienen iguales, y el mergeChunk helper de arriba ya maneja el formato de streaming de iOS. Los requisitos del dispositivo difieren (iOS 26 y un dispositivo compatible con Apple Intelligence). Nuestra guía sobre Apple Intelligence en una app de Capacitor cubre ese aspecto.

Pruebas

  • Usa un teléfono real compatible. Los emuladores no proporcionan AICore con Gemini Nano.
  • Registra el setModel mensaje de rechazo. Te indica exactamente qué estado reporta AICore.
  • En un dispositivo recién configurado o restablecido, espera a que AICore complete su configuración inicial mientras está en línea, y luego reintenta.
  • Prueba tus prompts en la versión más baja de Nano que soportes. Los prompts más cortos y explícitos son más estables entre versiones.

Solución de problemas

«Gemini Nano no está disponible en este dispositivo». El dispositivo no está en la lista de Google, el bootloader está desbloqueado o AICore aún no está configurado.

«Gemini Nano es descargable pero no ha sido descargado». El dispositivo lo admite, pero el modelo no está presente. Ofrece el fallback de Gemma o reintenta más tarde.

«Sesión de chat no encontrada». Llamaste a sendMessage con un chat creado antes de un nuevo setModel. Cargar un modelo borra los chats existentes, así que crea uno nuevo.

«Modelo no listo». setModel falló o no se llamó antes de createChat.

La salida se detiene a mitad de frase. Has alcanzado el límite de salida. Pide una respuesta más corta o divide la tarea.

Errores cuando la app pasa a segundo plano. La inferencia es solo en primer plano. Cancela el estado de la UI al pausar y permite que el usuario reintente.

Privacidad y revisión de la tienda

Los prompts y las respuestas se quedan en el dispositivo con Gemini Nano, lo que simplifica tu formulario de seguridad de datos. Los términos de ML Kit de Google aún mencionan el procesamiento de métricas, así que describe el uso de IA en el dispositivo en tu política de privacidad. Si añades el fallback de Gemma, la descarga del modelo viene de Hugging Face, así que menciona también esa solicitud de red.

Los prompts y el copy de la UI para funciones de IA cambian a menudo. Si necesitas ajustarlos después del lanzamiento, actualizaciones Live Update de Capgo te permiten publicar nuevos web code sin esperar a la revisión de la tienda. Para una visión más amplia de la IA en apps híbridas, lee por qué Capacitor funciona bien para apps móviles con IA.

Resumen

Gemini Nano ofrece a las apps de Capacitor generación de texto gratuita, privada y sin conexión en teléfonos Android compatibles. Carga con setModel({ path: 'Gemini Nano' }), transmite mediante textFromAi, mantén los prompts y las salidas cortos, respeta las reglas de primer plano y de cuota, y conserva un fallback de Gemma o en la nube para los muchos dispositivos que no lo tienen.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.