◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down today (10/23). Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down today (10/23). Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/Dev Tools
⟐ Dev Tools/2026-06-25Advanced

Gemini API × Android Jetpack Compose Complete Integration Guide — Production Design Patterns for Kotlin Native AI Apps

Build native Android AI apps with Kotlin and Jetpack Compose. Covers Google AI SDK, MVVM, multimodal chat UI, Room DB, WorkManager, and production security.

android8jetpack-compose3kotlin4gemini-api288google-ai-sdkviewmodelcoroutines

✦ Premium Article

Setup and context: Why Android Native × Gemini API?

As AI-powered mobile app development options multiply, building with native Android (Kotlin + Jetpack Compose) and the Gemini API offers unique advantages that cross-platform frameworks simply cannot match.

Deep OS integration is the primary differentiator. Android's Camera2 API, MediaStore, WorkManager, and notification system all work seamlessly with Kotlin coroutines, enabling peak performance for background processing and media operations. Jetpack Compose's declarative UI model is also a natural fit for streaming responses—dynamic content updates that would require complex state management elsewhere become surprisingly elegant with StateFlow and collectAsStateWithLifecycle.

On the ecosystem side, the Google AI SDK for Android is purpose-built for this combination. It handles the gRPC transport layer, manages Bitmap encoding for multimodal requests, and exposes Kotlin Flow-based APIs that slot directly into a modern MVVM architecture. You get first-class support for gemini-2.0-flash, gemini-2.5-pro, and future models without waiting for third-party adapters.

This guide walks you through a complete, production-ready design covering:

  • Secure SDK integration with Gradle Kotlin DSL and secrets-gradle-plugin
  • Clean MVVM architecture with ViewModel + StateFlow + Repository
  • Text and image multimodal chat UI with Jetpack Compose
  • Conversation history persistence with Room Database
  • Background AI summarization tasks with WorkManager
  • Hilt dependency injection for testable, modular code
  • A testing strategy using Compose Testing, Hilt Test, and fake repositories

Setting Up Your Development Environment

Prerequisites

  • Android Studio Koala (2024.1.1) or later
  • Kotlin 2.0+
  • Android Gradle Plugin 8.4+
  • A Gemini API key from Google AI Studio (free at aistudio.google.com)
  • minSdk 26+ recommended (some SDK features require it)
  • Basic familiarity with Jetpack Compose, Coroutines, and Hilt

Gradle Configuration (Kotlin DSL)

We'll use Version Catalog (libs.versions.toml) for clean dependency management across modules.

# gradle/libs.versions.toml
[versions]
generativeai = "0.9.0"
room = "2.6.1"
lifecycle = "2.8.4"
hilt = "2.51"
coroutines = "1.8.1"
workmanager = "2.9.1"
coil = "2.7.0"
 
[libraries]
google-ai-generativeai = { group = "com.google.ai.client.generativeai", name = "generativeai", version.ref = "generativeai" }
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" }
lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version = "1.2.0" }
workmanager-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workmanager" }
hilt-work = { group = "androidx.hilt", name = "hilt-work", version = "1.2.0" }
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" }
coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" }
 
[plugins]
secrets-gradle-plugin = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version = "2.0.1" }

Configure app/build.gradle.kts:

// app/build.gradle.kts
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.hilt)
    alias(libs.plugins.ksp)
    alias(libs.plugins.secrets.gradle.plugin)
}
 
android {
    compileSdk = 35
    defaultConfig {
        minSdk = 26
        targetSdk = 35
        applicationId = "com.yourcompany.geminiapp"
    }
    buildFeatures {
        compose = true
        buildConfig = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.14"
    }
}
 
dependencies {
    // Gemini
    implementation(libs.google.ai.generativeai)
 
    // Room
    implementation(libs.room.runtime)
    implementation(libs.room.ktx)
    ksp(libs.room.compiler)
 
    // Lifecycle + ViewModel
    implementation(libs.lifecycle.viewmodel.compose)
    implementation(libs.lifecycle.runtime.compose)
 
    // Hilt
    implementation(libs.hilt.android)
    ksp(libs.hilt.compiler)
    implementation(libs.hilt.navigation.compose)
    implementation(libs.hilt.work)
 
    // WorkManager
    implementation(libs.workmanager.ktx)
 
    // Coroutines
    implementation(libs.kotlinx.coroutines.android)
 
    // Image loading
    implementation(libs.coil.compose)
}

Protecting Your API Key with secrets-gradle-plugin

Never hardcode your API key in source code. The secrets-gradle-plugin reads from local.properties and injects values as BuildConfig fields, keeping secrets out of version control entirely.

# local.properties (add to .gitignore immediately)
GEMINI_API_KEY=YOUR_GEMINI_API_KEY
// In app/build.gradle.kts
secrets {
    propertiesFileName = "local.properties"
    defaultPropertiesFileName = "local.defaults.properties"
}

Create local.defaults.properties for CI environments:

# local.defaults.properties (safe to commit)
GEMINI_API_KEY=placeholder_key_for_ci

This makes BuildConfig.GEMINI_API_KEY available in your Kotlin code. The plugin handles everything at compile time—no reflection, no runtime file reads.


✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Normalize Gemini failures into seven categories and surface per-device error rates with Crashlytics custom keys
✦Separate expected failures (safety, 429) from real crashes so genuine NPEs do not get buried in non-fatals
✦Survive process death and rotation mid-stream with SavedStateHandle partial stashing plus Room as the source of truth
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

◈ API / SDK2026-06-23
Integrating Gemini 3.2 Pro Function Calling into iOS/Android Apps: Production Design Patterns
A practical guide to integrating Gemini 3.2 Pro Function Calling into iOS and Android apps. Includes working SwiftUI, Kotlin, and Python code, plus production patterns proven in a real indie wallpaper app — cost, latency, staged rollout, and regression testing.
⟐ Dev Tools2026-08-21
Why My Length Limit Only Failed on the English Notifications, and the Width-Based Fit That Replaced It
I had Gemini write push notifications in Japanese and English, and only the English ones came out truncated on real devices. The culprit was measuring length in characters. Here are the measured widths and the post-generation fitting code that fixed it.
⟐ Dev Tools2026-08-10
Finding the questions your help docs never answer, by asking Gemini to write the quiz
When support keeps asking something your help page already covers, generate questions from that page and check whether the page alone can answer them. A two-pass audit pipeline with call design and cost math.