要在 Capacitor 应用中使用 Gemini Nano,请安装 @capgo/capacitor-llm,调用 setModel({ path: 'Gemini Nano' }) 在 Android 上,然后发起聊天,并将回复通过 textFromAi event 流式传输。该插件通过 Google 的 ML Kit GenAI Prompt API 与 Gemini Nano 通信,该 API 在 Android 的 AICore 系统服务中运行模型,因此文本不会离开手机。
本指南涵盖 Gemini Nano 的运行方式、支持设备、具体的插件调用、流式传输、配额与限制、针对不受支持手机的 Gemma 回退方案,以及同一个 code 如何在 iOS 上接入 Apple Intelligence。
Gemini Nano 如何在 Android 上运行
Gemini Nano 是 Google 最小的 Gemini 模型,专为手机打造。应用不会将它打包进去。Android 的 AICore 服务会下载、更新它并运行推理,应用则通过 ML Kit GenAI API:
- Prompt API: 自由形式的文本提示,该插件使用的 API(
com.google.mlkit:genai-prompt). - 功能 API: 固定任务,例如摘要、校对、改写和图像描述。
Google 以 beta 形式发布 Prompt API,没有 SLA 和弃用政策,所以不同版本之间行为可能变化,请把集成封装在自己的小型 wrapper 里。
由于推理在本地进行,你能得到云模型给不了的三点:可离线运行、没有按 token 计费的成本、用户文本留在设备上。代价是模型更小、上下文和输出都更短,所以要挑合适的任务:改写、总结笔记、给消息分类、提取字段、起草简短回复。
支持的设备与要求
Google 在 ML Kit GenAI 网站上按 API 发布支持列表,并按 Gemini Nano 版本(nano-v2、nano-v3、nano-v4)分组。对于 Prompt API,覆盖 Pixel 9 及之后机型、近期的 Samsung Galaxy S 和 Z 系列旗舰,以及 OnePlus、OPPO、Xiaomi、vivo、Honor、realme、Motorola 等品牌的近期旗舰。在向某款设备承诺功能之前,先查一下最新列表。
每台受支持的设备还需要:
| 要求 | 详情 |
|---|---|
| Android 版本 | API level 26 或更高(插件会检查) |
| 引导加载程序 | Locked。Google 不支持在已解锁的 bootloader 上使用 GenAI API |
| AICore | 已就绪并完成设置。设备设置或重置后,可能需要一段时间才能完成 |
| 应用状态 | 推理期间,您的应用必须处于前台最顶层 |
不同的 Nano 版本对相同的 prompt 可能返回不同的输出。请在你关注的每个版本上,至少用一台设备测试你的 prompt。
安装插件
bun add @capgo/capacitor-llm
bunx cap sync
该 plugin 遵循 Capacitor 的主版本号:Capacitor 8 请搭配 8.x 使用。Gemini Nano 不需要修改 Android manifest。完整参考: 插件文档 以及 plugin 页面.
第 1 步:加载 Gemini Nano 并检查就绪状态
setModel 使用特殊路径 'Gemini Nano' 向 ML Kit 查询模型状态。状态可用时 resolve,否则 reject,并在错误消息中包含该状态:
| 来自 AICore 的状态 | 插件行为 |
|---|---|
| 可用 | setModel resolve, readinessChange 触发 ready |
| 可下载 | 拒绝:“Gemini Nano 可下载,但尚未在此设备上下载” |
| 正在下载 | 以“下载中”状态拒绝 |
| 不可用 | 拒绝:“Gemini Nano 在此设备上不可用” |
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';
}
插件本身不会启动 AICore 模型下载。如果设备报告为可下载,模型通常要等其他应用或系统请求后才会下载,所以请在后续启动时再检查,不要永久隐藏该功能。
第 2 步:创建对话并流式输出回答
Chat 会保留对话历史。在 Android 上, sendMessage 在生成开始时即 resolve,文本通过事件到达。将其包装为一个在 ... 时 resolve 的 Promise 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()));
}
}
将其用于实际功能,例如起草对客户评价的回复:
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() 不接受任何选项,因此请将指令放在第一条消息的开头。为每个任务创建新的 Chat。在 Gemini Nano 路径中,插件会在内存中保留历史并随每条消息发送,因此长对话会迅速耗尽输入预算。
设计时需考虑的限制
| 限制 | 值 | 处理方式 |
|---|---|---|
| 输入 | 每次请求约 4,000 个 token 以内(Google) | 保持对话简短,精简长文档 |
| 输出 | 该插件将 Gemini Nano 的响应限制在 256 个 token 以内 | 要求简短输出,拆分长任务 |
| 前台 | 仅在应用处于前台时进行推理 | 切勿在后台任务中运行 |
| 配额 | 每个应用的配额, BUSY 以及电池配额错误 |
使用防抖,避免每次按键都触发生成 |
| 并发 | 每个对话只允许一个生成任务 | 流式输出时禁用发送按钮 |
| 速度 | 每个段落耗时数秒 | 始终流式输出到 UI |
把配额错误当作临时问题。显示重试选项,而不是错误弹窗。
回退方案:Gemini Nano 不可用时使用 Gemma 4
目前大多数在用的 Android 手机都没有 Gemini Nano。同一个插件可以通过 LiteRT-LM 运行开源的 Gemma 模型,这样只需保留一个 API。模型体积很大,通常超过 1GB,所以只在用户主动选择后再下载,最好在 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();
}
}
然后在启动时选择引擎:
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';
}
如果两者都不可行,就隐藏该功能或调用云端模型。不要让本地 AI 阻塞核心流程。
iOS 上相同的 code
在 iOS 上,该插件通过 Foundation Models 框架使用 Apple Intelligence。只需改一行代码:
await CapgoLLM.setModel({ path: 'Apple Intelligence' });
createChat, sendMessage,事件保持不变,且 mergeChunk 上文的 helper 已处理 iOS 的流式传输格式。设备要求不同(需 iOS 26 及支持 Apple Intelligence 的设备)。我们关于 在 Capacitor 应用中使用 Apple Intelligence 的指南涵盖了这部分。
测试
- 请使用受支持的真机。模拟器不提供带 Gemini Nano 的 AICore。
- 记录
setModel拒绝消息。它会准确告诉你 AICore 报告的具体状态。 - 在全新设置或重置的设备上,请在联网状态下等待 AICore 完成初始设置,然后重试。
- 在支持的最低 Nano 版本上测试 prompt。更短、更明确的 prompt 在不同版本间更稳定。
故障排除
“Gemini Nano 在此设备上不可用”。 设备不在 Google 的名单中、bootloader 已解锁,或者 AICore 尚未设置完毕。
“Gemini Nano 可下载,但尚未下载”。 设备支持,但模型不存在。提供 Gemma 回退方案,或稍后重试。
“未找到聊天会话”。 您调用了 sendMessage ,但所用聊天会话是在新的模型加载前创建的 setModel。加载模型会清除现有聊天,请创建新会话。
“模型尚未就绪”。 setModel 失败,或之前未被调用 createChat.
输出中途停止。 已达到输出上限。请要求更简短的回答,或拆分任务。
应用进入后台时会报错。 推理仅限前台运行。暂停时取消 UI 状态,并让用户重试。
隐私与商店审核
使用 Gemini Nano 时,Prompt 和响应都保留在设备端,这能简化你的数据安全表单。Google 的 ML Kit 条款仍会提到指标处理,所以请在隐私政策中说明你对端侧 AI 的使用。如果你加入 Gemma 回退方案,模型下载来自 Hugging Face,也要说明这个网络请求。
AI 功能的 Prompt 和 UI 文案经常变化。如果发布后需要调整, Capgo 实时更新 让你无需等待商店审核即可发布新的 Web code。想全面了解混合应用中的 AI,请阅读 为什么 Capacitor 非常适合 AI 移动应用.
总结
Gemini Nano 为受支持的 Android 手机上的 Capacitor 应用提供免费、私密、离线的文本生成。使用以下代码加载: setModel({ path: 'Gemini Nano' }),并通过以下代码进行流式传输: textFromAi,保持 Prompt 和输出简短,遵守前台运行和配额规则,并为大量不支持该功能的设备保留 Gemma 或云端回退方案。