Google Gemini in einer Android-App (Kotlin, über dein eigenes Backend)
Ein KI-Feature in eine Kotlin-App bringen – mit Google Gemini. Warum der API-Key nie in die App gehört, wie der generateContent-Aufruf aussieht und wie du ihn sauber aus einer Coroutine startest.
Du willst ein KI-Feature in deine Android-App bringen – eine Textgenerierung, eine Zusammenfassung, einen Assistenten? Google Gemini ist dafür eine naheliegende Wahl. Der wichtigste Grundsatz vorweg: Der API-Key gehört nicht in die App. Eine APK lässt sich dekompilieren; jeder eingebettete Schlüssel ist damit öffentlich. Die App spricht deshalb mit deinem eigenen Backend, das den Key hält und an Gemini weiterreicht.
Der Aufruf über dein Backend (Retrofit + Coroutines)
import retrofit2.http.Body
import retrofit2.http.POST
// 1) Datenmodelle für deinen eigenen Endpunkt
data class AskRequest(val prompt: String)
data class AskResponse(val text: String)
// 2) Retrofit-Interface – zeigt auf DEIN Backend, nicht auf Google
interface AiApi {
@POST("api/gemini")
suspend fun ask(@Body body: AskRequest): AskResponse
}
// 3) Aufruf aus dem ViewModel, main-sicher dank suspend
class ChatViewModel(private val api: AiApi) : ViewModel() {
private val _answer = MutableStateFlow("")
val answer: StateFlow<String> = _answer.asStateFlow()
fun ask(prompt: String) {
viewModelScope.launch {
_answer.value = try {
api.ask(AskRequest(prompt)).text // Netzwerk läuft off-main (Retrofit)
} catch (e: Exception) {
"Fehler: ${e.message}"
}
}
}
}Dein Backend ruft dann Gemini auf – hier liegt der Key sicher:
// Server-Seite (Ktor/Spring o.ä.) – nur zur Veranschaulichung des Gemini-Calls
// POST https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=$KEY
// Body:
// { "contents": [ { "parts": [ { "text": "<prompt>" } ] } ] }
// Antwort: candidates[0].content.parts[0].textWarum dieser Umweg – und was er dir bringt
- Sicherheit: Der Key bleibt auf dem Server. Wird er kompromittiert, tauschst du ihn an *einer* Stelle, ohne ein App-Update auszurollen.
- Kontrolle: Im Backend kannst du Anfragen begrenzen (Rate-Limiting), protokollieren und den System-Prompt zentral pflegen – ohne die App neu zu veröffentlichen.
- Austauschbarkeit: Ob dahinter Gemini, Claude oder ChatGPT steckt, merkt die App nicht. Du kannst den Anbieter wechseln, ohne eine Zeile Kotlin anzufassen.
Das StateFlow liest du in Compose übrigens am besten mit collectAsStateWithLifecycle() – so wird nur gesammelt, wenn der Screen sichtbar ist.
Du willst eine Android-App in Kotlin & Compose mit sinnvollem KI-Feature? Melde dich.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
withContext(Dispatchers.IO) – schwere Arbeit vom Main-Thread nehmen
Datei lesen oder ein Bild dekodieren blockiert den Main-Thread und ruckelt die UI. Mit withContext(Dispatchers.IO) schiebst du blockierende Arbeit sauber auf einen Hintergrund-Thread.
Navigation in Compose – NavHost mit Argumenten
Von der Liste zum Detail und mit einer ID zurück: Navigation Compose macht das mit NavHost, Routen und typisierten Argumenten. So richtest du den Grundfluss sauber ein.
UI-State als sealed interface – Loading, Success, Error sauber modellieren
Zwei Booleans für "lädt" und "Fehler"? Das gibt unmögliche Zustände. Mit einem sealed interface bildest du genau die Fälle ab, die es wirklich gibt – und der Compiler hilft dir.