Adding On-Device AI to an Android App with Gemini Nano

AndroidGemini NanoOn-Device AIML Kit

On-device AI finally crossed the line from demo to shippable on Android. With Gemini Nano running through AICore, you can summarize a chat thread, rewrite a message in a different tone, proofread text, or describe an image — all without a network call, without a per-request bill, and without user data leaving the phone. For a class of features that used to require a cloud round-trip, that's a meaningful shift.

The catch, and the thing most tutorials gloss over, is that on-device AI on Android is a conditional capability. It exists on a subset of devices, the model is small and task-specific, and you must design for graceful absence. Here's how to add Gemini Nano features properly, what the APIs actually give you, and where the sharp edges are.

The pieces: AICore, Gemini Nano, and ML Kit GenAI

Three layers matter:

For lower-level, prompt-based access there's the experimental generative APIs, but the ML Kit GenAI feature APIs are where reliability lives today.

Always check availability first

The single most important habit: never assume the feature exists. Device support is narrow (Pixel 9 family, recent Galaxy S flagships, and expanding), and even on a supported device the model may still need to download. Check status and drive UI from it.

val summarizer = Summarization.getClient(
    SummarizerOptions.builder(context)
        .setInputType(InputType.ARTICLE)
        .setOutputType(OutputType.THREE_BULLETS)
        .setLanguage(Language.ENGLISH)
        .build()
)

when (summarizer.checkFeatureStatus().await()) {
    FeatureStatus.AVAILABLE -> runSummary(summarizer)
    FeatureStatus.DOWNLOADABLE -> {
        // trigger download, show progress, then run
        summarizer.downloadFeature(downloadCallback)
    }
    FeatureStatus.DOWNLOADING -> showDownloadingState()
    FeatureStatus.UNAVAILABLE -> useCloudFallbackOrHideFeature()
}

UNAVAILABLE is not an edge case — it's the majority of the installed base right now. Decide up front whether the feature degrades to a cloud call or simply hides, and make that decision per feature.

Running a summarization

Once available, the API is stream-friendly, which matters for perceived latency because even on-device generation isn't instant:

val request = SummarizationRequest.builder(longText).build()

summarizer.runInference(request) { result ->
    // streamed chunks; append to UI as they arrive
    appendToUi(result.summary)
}

On a Pixel 9 I've seen short summaries complete in a couple of seconds with the model already resident. The first run after a cold start is slower because AICore loads the model into memory; subsequent runs are quick. Stream the output so the user sees progress rather than a spinner.

What the model is good at (and not)

Gemini Nano is a small model. Calibrate expectations accordingly:

Good fit Poor fit
Summarize a thread or article Multi-step reasoning
Rewrite tone (formal ↔ casual) Long-context analysis (many pages)
Proofread / fix grammar Factual Q&A requiring world knowledge
Describe an image for accessibility Anything needing consistent output across all devices

The task-specific ML Kit APIs exist precisely because a small model does far better on a narrow, well-defined job than on an open prompt. Lean into that. If your feature needs genuine reasoning or long context, that's a cloud job — possibly with RAG — and trying to force it onto Nano will disappoint users on the few devices that even run it.

Why bother, given the device limits

Three reasons make on-device worth the conditional complexity:

Privacy. The text or image never leaves the phone. For messaging, health, journaling, or anything sensitive, that's a feature you can put in marketing copy — and it sidesteps a pile of mobile privacy and GDPR obligations that come with shipping user content to a server.

Offline. Summarization on the subway, proofreading on a plane. No connectivity dependency.

Cost. Zero marginal cost per inference. At scale, moving even a fraction of requests on-device meaningfully dents a cloud LLM bill.

Production checklist

Things I'd verify before shipping a Gemini Nano feature:

On-device AI is a great addition to the Android toolbox — it's not a replacement for cloud models, it's a complementary tier for well-scoped, privacy-sensitive, offline-friendly tasks. Treat it as one, design for absence, and it becomes a differentiator rather than a support headache. It pairs naturally with the broader on-device AI for Android privacy story.

Resources

Frequently asked questions

What is Gemini Nano and where does it run?

Gemini Nano is Google's smallest Gemini model, designed to run on-device through the AICore system service on supported Android phones. Inference happens locally, so data never leaves the device and features work offline.

Which Android devices support Gemini Nano?

Gemini Nano runs on a limited set of higher-end devices with the required NPU and AICore support — Pixel 9 series, recent Samsung Galaxy S flagships, and a growing list. Always check availability at runtime and provide a fallback for unsupported devices.

Should I use Gemini Nano or a cloud model?

Use Gemini Nano when privacy, offline support, and zero per-request cost matter and the task is well-scoped (summarize, rewrite, proofread, describe). Use a cloud model for complex reasoning, long context, or when consistent quality across all devices is required.

Hiring a senior Android / Flutter engineer?

I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.

Get in touch →