Salta al contenuto principale

Come usare Gemini Nano in un'app Capacitor

Usa Gemini Nano in un'app Capacitor per l'IA on-device su Android: supporto device, controlli AICore, streaming con @capgo/capacitor-llm e fallback con Gemma.

Come usare Gemini Nano in un'app Capacitor

Per usare Gemini Nano in un'app Capacitor, installa @capgo/capacitor-llm, chiama setModel({ path: 'Gemini Nano' }) su Android, poi crea una chat e ricevi la risposta in streaming tramite l' textFromAi evento. Il plugin comunica con Gemini Nano tramite il Prompt API di Google ML Kit GenAI, che esegue il modello all'interno del servizio AICore di Android, così il testo non lascia mai il telefono.

Questa guida spiega come funziona Gemini Nano, quali dispositivi lo supportano, le chiamate esatte al plugin, lo streaming, quote e limiti, un fallback con Gemma per i telefoni non supportati e come lo stesso code raggiunge Apple Intelligence su iOS.

Come funziona Gemini Nano su Android

Gemini Nano è il modello Gemini più piccolo di Google, progettato per gli smartphone. Le app non lo includono nel bundle. Android's AICore di Android lo scarica, lo aggiorna ed esegue l'inferenza; le app vi accedono tramite le API ML Kit GenAI:

  • Prompt API: prompt di testo libero, il API utilizzato da questo plugin (com.google.mlkit:genai-prompt).
  • API delle funzionalità: task predefiniti come riassunto, correzione bozze, riscrittura e descrizione di immagini.

Google rilascia il Prompt API in beta, senza SLA o policy di deprecation; aspettati cambiamenti tra una release e l'altra e mantieni l'integrazione dietro un tuo wrapper.

Poiché l'inferenza è locale, ottieni tre vantaggi che un modello cloud non può darti: funziona offline, non ha costi per token e il testo dell'utente resta sul dispositivo. Il compromesso è un modello più piccolo con context e output limitati, quindi scegli task adatti: riscrittura, riassunto di note, classificazione messaggi, estrazione campi o bozze di risposte brevi.

Dispositivi supportati e requisiti

Google pubblica la lista dei supportati per API sul sito ML Kit GenAI, raggruppati per versione di Gemini Nano (nano-v2, nano-v3, nano-v4). Per il Prompt API sono coperti Pixel 9 e successivi, i recenti flagship Samsung Galaxy S e Z, e i modelli top di gamma di OnePlus, OPPO, Xiaomi, vivo, Honor, realme, Motorola e altri. Controlla la lista aggiornata prima di promettere una feature su un dispositivo specifico.

Ogni dispositivo supportato richiede inoltre:

Requisito Dettaglio
Versione Android API livello 26 o superiore (il plugin effettua il controllo)
Bootloader Locked. Google non supporta le API GenAI su bootloader sbloccati
AICore In corso. Dopo il setup o il reset di un dispositivo, l'operazione potrebbe richiedere tempo.
Stato dell'app L'app deve essere in primo piano durante l'inferenza

Versioni diverse di Nano possono restituire output differenti per lo stesso prompt. Testa i tuoi prompt su almeno un dispositivo per ogni versione che intendi supportare.

Installa il plugin

bun add @capgo/capacitor-llm
bunx cap sync

Il plugin segue la major version di Capacitor: usa 8.x con Capacitor 8. Non sono necessarie modifiche all'Android manifest per Gemini Nano. Riferimento completo: docs del plugin e pagina del plugin.

Passaggio 1: Carica Gemini Nano e verifica la disponibilità

setModel con il percorso speciale 'Gemini Nano' interroga ML Kit sullo stato del modello. Risolve quando lo stato è disponibile, altrimenti rifiuta con un messaggio che include lo stato:

Stato da AICore Comportamento del plugin
disponibile setModel risolve, readinessChange emette ready
scaricabile Rifiuto: “Gemini Nano è scaricabile ma non è stato scaricato su questo dispositivo”
in fase di download Rejects con lo stato di download in corso
non disponibile Errore: “Gemini Nano non è disponibile su questo 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';
}

Il plugin non avvia direttamente il download del modello AICore. Se il dispositivo riporta 'downloadable', il modello viene solitamente scaricato dopo una richiesta di un'altra app o del sistema; quindi, riprova al prossimo avvio invece di nascondere la funzione permanentemente.

Passaggio 2: Crea una chat e fai lo streaming della risposta

Una chat mantiene la cronologia della conversazione. Su Android, sendMessage si risolve non appena inizia la generazione, e il testo arriva tramite eventi. Avvolgilo in una promise che si risolve quando 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()));
  }
}

Usalo per una funzionalità reale, ad esempio per bozzare una risposta a una recensione di 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() non accetta opzioni, quindi inserisci le istruzioni all'inizio del primo messaggio. Crea una nuova chat per ogni task. Con Gemini Nano il plugin mantiene la cronologia in memoria e la invia con ogni messaggio, quindi le chat lunghe consumano rapidamente il budget di input.

Limiti di progettazione per

Limite Valore Cosa fare
Input Circa 4.000 token per richiesta (Google) Mantieni le chat brevi, accorcia i documenti lunghi
Output Il plugin limita le risposte di Gemini Nano a 256 token Richiedi output brevi, dividi i task lunghi
Foreground Inference solo quando l'app è in primo piano Non eseguirlo mai da task in background
Quota Quote per singola app, BUSY ed errori di quota della batteria Debounce, evita la generazione a ogni keystroke
Concorrenza Una generazione per chat Disabilita il tasto invio durante lo streaming
Velocità Diversi secondi per un paragrafo Fai sempre lo streaming verso la UI

Gestisci l'errore di quota come temporaneo. Mostra un'opzione di retry invece di un dialog di errore.

Fallback: Gemma 4 se Gemini Nano manca

La maggior parte degli smartphone Android attuali non ha Gemini Nano. Lo stesso plugin può eseguire modelli open Gemma tramite LiteRT-LM, così mantieni un unico API. Il modello è grande, spesso oltre un gigabyte, quindi scaricalo solo dopo l'opt-in dell'utente, idealmente via 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();
  }
}

Poi scegli il motore all'avvio:

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

Se nessuno dei due è possibile, nascondi la feature o chiama un modello cloud. Non bloccare i flussi core per l'IA locale.

Lo stesso code su iOS

Su iOS il plugin usa Apple Intelligence tramite il framework Foundation Models. Cambia una riga:

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

createChat, sendMessage, e gli eventi rimangono invariati, e il mergeChunk l'helper sopra gestisce già il formato streaming per iOS. I requisiti del dispositivo variano (iOS 26 e un dispositivo compatibile con Apple Intelligence). La nostra guida su Apple Intelligence in un'app Capacitor tratta questo aspetto.

Testing

  • Usa un telefono reale supportato. Gli emulatori non forniscono AICore con Gemini Nano.
  • Logga il setModel messaggio di rifiuto. Ti indica esattamente quale stato riporta AICore.
  • Su un dispositivo appena configurato o resettato, attendi che AICore completi la configurazione iniziale online, quindi riprova.
  • Testa i tuoi prompt sulla versione Nano più bassa che supporti. Prompt brevi ed espliciti sono più stabili tra le varie versioni.

Troubleshooting

“Gemini Nano non è disponibile su questo dispositivo”. Il dispositivo non è nell'elenco di Google, il bootloader è sbloccato o AICore non è ancora configurato.

“Gemini Nano è scaricabile ma non è stato scaricato”. Il dispositivo lo supporta ma il modello non è presente. Offri il fallback con Gemma o riprova più tardi.

“Sessione chat non trovata”. Hai chiamato sendMessage con una chat creata prima di un nuovo setModel. Caricare un modello cancella le chat esistenti, quindi creane una nuova.

“Modello non pronto”. setModel è fallito o non è stato chiamato prima di createChat.

L'output si interrompe a metà frase. Hai raggiunto il limite di output. Chiedi una risposta più breve o dividi il task.

Errori quando l'app passa in background. L'inferenza funziona solo in foreground. Annulla lo stato della UI in pausa e lascia che l'utente riprovi.

Privacy e revisione degli store

Con Gemini Nano, prompt e risposte rimangono sul dispositivo, semplificando il modulo sulla sicurezza dei dati. I termini di Google ML Kit menzionano ancora l'elaborazione delle metriche, quindi descrivi l'uso dell'IA on-device nella tua privacy policy. Se aggiungi il fallback Gemma, il download del modello avviene tramite Hugging Face, quindi menziona anche quella richiesta di rete.

I prompt e la UI copy per le funzioni IA cambiano spesso. Se devi ottimizzarli dopo il rilascio, live update di Capgo puoi distribuire nuovi code web senza attendere la revisione degli store. Per un quadro più ampio sull'IA nelle app ibride, leggi perché Capacitor funziona bene con le app mobile IA.

In sintesi

Gemini Nano offre alle app Capacitor la generazione di testo gratuita, privata e offline sui telefoni Android supportati. Caricalo con setModel({ path: 'Gemini Nano' }), usa lo streaming tramite textFromAi, mantieni prompt e output brevi, rispetta le regole di foreground e quota, e tieni un fallback Gemma o cloud per i molti dispositivi che non lo supportano.

Live update per le app Capacitor

Quando un bug del web layer è live, rilascia il fix tramite Capgo invece di aspettare giorni per l'approvazione degli store. Gli utenti ricevono l'update in background, mentre le modifiche native restano nel normale percorso di review.

Ultime dal Blog

Capgo ti offre tutti gli insight necessari per creare un'app mobile davvero professionale.