Release-App-Bundle bauen
Google Play akzeptiert für neue Apps nur Android App Bundles (.aab). Flutter baut eins mit einem einzigen Befehl, und der Release-Modus ist Standard. Prüfe vorher zwei Dinge; beide lassen sich schwer korrigieren, sobald Tester die App haben.
Application ID festlegen
Gib
applicationIdinandroid/app/build.gradle.ktseinen eindeutigen Wert in umgekehrter Domain-Schreibweise, z. B.com.yourcompany.app. Nach dem ersten Upload zu Google Play lässt sie sich nicht mehr ändern.INTERNET-Berechtigung prüfen
Wenn die App aufs Netzwerk zugreift, muss
android/app/src/main/AndroidManifest.xmldie Berechtigungandroid.permission.INTERNETdeklarieren. Die Debug- und Profile-Manifeste enthalten sie, das Release-Manifest nur, wenn du sie hinzufügst.Bundle bauen
Führe den Befehl unten im Projektstamm aus. Flutter schreibt das Bundle nach
build/app/outputs/bundle/release/.
flutter build appbundleDu nutzt Flavors? Baue den, den du veröffentlichen willst, z. B. flutter build appbundle --flavor production, und prüfe, dass er den Produktions-Paketnamen und die Produktions-API-Schlüssel verwendet.
Signieren: Upload-Schlüssel und Play App-Signatur
Für neue Apps ist die Play App-Signatur Pflicht: Google verwahrt den App-Signaturschlüssel, und du signierst jeden Upload mit deinem eigenen Upload-Schlüssel. Geht der Upload-Schlüssel verloren, kannst du Google um ein Zurücksetzen bitten; deine App ist damit nicht verloren. Erstelle den Schlüssel mit keytool:
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
-storetype JKS -keysize 2048 -validity 10000 -alias uploadLege dann android/key.properties mit den Passwörtern und dem Pfad zum Keystore an. Diese Datei und die .jks-Datei gehören nicht in die Versionsverwaltung:
storePassword=<keystore password>
keyPassword=<key password>
keyAlias=upload
storeFile=/Users/<you>/upload-keystore.jksLade die Datei in android/app/build.gradle.kts und lass den Build-Typ release die neue Signaturkonfiguration verwenden:
import java.util.Properties
import java.io.FileInputStream
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
android {
// ...
signingConfigs {
create("release") {
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
storeFile = keystoreProperties.getProperty("storeFile")?.let { file(it) }
storePassword = keystoreProperties.getProperty("storePassword")
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
}
}
}Ältere Projekte nutzen build.gradle (Groovy) statt build.gradle.kts; die Felder sind dieselben. Führe nach Änderungen an Gradle-Dateien flutter clean aus.
Versionscode und Ziel-API-Level
Jeder Upload braucht einen höheren Versionscode als alle Bundles, die du je hochgeladen hast, egal in welchem Track. In Flutter ist das die Zahl nach dem + in pubspec.yaml:
version: 1.0.0+11.0.0 wird zum Versionsnamen, den Nutzer sehen, 1 ist der Versionscode. Erhöhe ihn auf +2, +3 usw. oder überschreibe beides beim Build mit --build-name und --build-number.
Seit dem 31. August 2026 müssen neue Apps und Updates Android 16 (API-Level 36) oder höher als Ziel haben. Die Gradle-Datei nutzt targetSdk = flutter.targetSdkVersion, daher ist ein Flutter-Upgrade der übliche Weg, den Wert anzuheben. Ist deine Flutter-Version älter, setze targetSdk = 36 selbst und teste vor dem Upload auf einer aktuellen Android-Version.
Flutter-Fallen, die den geschlossenen Test verzögern
- Wiederverwendete Build-Nummer. Die Play Console lehnt ein Bundle ab, dessen Versionscode schon verwendet wurde. Erhöhe das
+Ninpubspec.yamlvor jedem Build, den du hochladen willst. - Verschleierung ohne Symbole.
--obfuscatefunktioniert nur zusammen mit--split-debug-info. Bewahre das Symbolverzeichnis jedes hochgeladenen Builds auf; sonst kannst du Absturzberichte von Testern nicht lesen. - Falscher Flavor. Mit Flavors lädt man schnell den Staging-Build mit Staging-Endpunkten hoch. Tester melden dann Fehler, die Produktionsnutzer nie sehen würden.
- Kein Netzwerk im Release. Fehlt die INTERNET-Berechtigung im Hauptmanifest, läuft die App im Debug-Modus und scheitert bei Testern stillschweigend.
- Debug-signiertes Bundle. Verwendet der Build-Typ
releasenoch die Debug-Signatur, lehnt die Play Console den Upload ab. - Plugins mit altem nativem Code. Plugins mit
.so-Bibliotheken müssen 16-KB-Speicherseiten unterstützen. Die Play Console warnt davor, und ab dem 1. Februar 2027 lassen sich Updates ohne Unterstützung nicht mehr veröffentlichen. Aktualisiere Plugins und das Flutter SDK vor dem Test, nicht mittendrin.
flutter build appbundle --obfuscate --split-debug-info=build/symbolsAbsturzberichte deiner Tester lesen
Tester kopieren Stacktraces in Fehlerberichte, und die Play Console sammelt Abstürze unter Beobachten und verbessern → Android Vitals → Abstürze und ANRs. Ein Flutter-Stacktrace hat zwei Hälften: den Dart-Teil, den --obfuscate in kurze, nichtssagende Namen verwandelt, und den Android-Teil, den R8 verkleinert. Flutter aktiviert die Code-Verkleinerung in Release-Builds immer, also plane für beides.
Dart-Symbole aufbewahren
Ein Build mit
--split-debug-infoschreibt pro Architektur eine Symboldatei, etwaapp.android-arm64.symbols. Bewahre den Ordner zusammen mit dem zugehörigen Versionscode auf: Die Datei eines anderen Builds kann den Stacktrace nicht entschlüsseln.Dart-Stacktraces entschlüsseln
Speichere den Stacktrace in einer Datei und übergib ihn zusammen mit der Symboldatei für die Architektur des Geräts an
flutter symbolize. Die meisten aktuellen Smartphones sind arm64.Die Java-Seite der Play Console überlassen
Ab Android Gradle Plugin 4.1 steckt die R8-Mapping-Datei im
.aab, sodass die Play Console Java- und Kotlin-Zeilen aus Plugins ohne separaten Upload entschleiert.
flutter symbolize -i crash.txt -d build/symbols/app.android-arm64.symbolsVerschleierung benennt nur Symbole um; sie verschlüsselt nichts und ist kein Ort für Geheimnisse. Code, der runtimeType.toString() mit einem Klassennamen vergleicht, bricht durch die Verschleierung, Enum-Namen bleiben dagegen lesbar.
Play Console kurz: vom geschlossenen Test zur Produktion
Sobald dein Flutter-Bundle gebaut und signiert ist, passiert der Rest in der Play Console und funktioniert für jedes Framework gleich. Hier die Checkliste; jedes Menü und jeden Bildschirm erklärt die vollständige Play-Console-Anleitung.
- App-Einrichtung abschließen: im Dashboard Datenschutzerklärung, App-Zugriff, Werbung, Altersfreigabe, Zielgruppe, Datensicherheit und Store-Eintrag.
- Release für den geschlossenen Test erstellen: unter Testen und veröffentlichen → Tests → Geschlossene Tests die Länder deiner Tester wählen, das
.aabhochladen und zur Prüfung senden. - Tester per Google Group hinzufügen: im Tab Tester die Gruppe eintragen und den Opt-in-Link teilen. Er funktioniert, sobald der Track Veröffentlicht zeigt.
- Mindestens 12 Tester 14 Tage ohne Unterbrechung im Opt-in halten. Interne Tests zählen nicht, und wer austritt und wiederkommt, beginnt seine 14 Tage von vorn.
- Während des Tests mindestens ein Update veröffentlichen und notieren, was Tester gefunden und was du geändert hast.
- Produktionszugang beantragen: im Dashboard den Antrag öffnen und die drei Abschnitte zu deinem Test, deiner App und deiner Produktionsreife beantworten. Die Entscheidung trifft Google; niemand kann eine Freigabe garantieren.
Plane Ausfälle ein: Gewinne mehr als 12 Tester, damit ein Abgang deinen Zeitplan nicht verschiebt. Alle Play-Console-Schritte ansehen.
Die vollständige Play-Console-Anleitung
Geschlossener Track, Google Group und Opt-in-Link, die Regel 12 Tester / 14 Tage und der Produktionsantrag, Schritt für Schritt auf einer Seite.
Fehlerbehebungen während des Tests ausliefern
In Flutter: Build-Nummer erhöhen, neu bauen und das neue Bundle in denselben geschlossenen Track hochladen.
flutter build appbundle --build-name=1.0.1 --build-number=2Starte vor jedem Upload den Release-Build auf einem echten Smartphone. flutter install installiert die Release-APK auf einem angeschlossenen Gerät und deckt fehlende Berechtigungen, falsche Flavors und reine Release-Abstürze in Minuten auf:
flutter build apk
flutter installUm genau das Bundle zu prüfen, das du gleich hochlädst, wandle es mit Googles bundletool in Geräte-APKs um oder lade es in den geschlossenen Track und installiere es mit einem Tester-Konto aus Google Play. So testest du, was Tester bekommen, einschließlich der geräteabhängigen Split-APKs von Play.
- Eine gezielte Änderung pro Update. Kleine Releases zeigen klar, welche Korrektur welchen Testerbericht beantwortet hat, und liefern konkrete Beispiele für das Formular zum Produktionszugang.
- Wechsle die Flutter-Version nicht mitten im Test, außer ein von Testern gemeldeter Fehler verlangt es. Ein SDK-Upgrade ändert die Engine, den nativen Code jedes Plugins und eventuell
targetSdkauf einmal. - Plane Zeit für die Prüfung ein. Jedes neue Release im geschlossenen Track geht an Google, bevor Tester es erhalten. Leg deine letzte Korrektur also nicht auf den letzten Tag.
Häufige Fragen
Brauche ich --obfuscate für einen geschlossenen Test?
Nein. Verschleierung ist optional und macht nur Dart-Symbole schwerer lesbar. Wenn du sie nutzt, kombiniere sie immer mit --split-debug-info und archiviere die Symbole, sonst sind die Abstürze deiner Tester unlesbar.
Welchen Versionscode sieht Google Play?
Die Zahl nach dem + in pubspec.yaml oder den Wert von --build-number, wenn du ihn übergibst. Flutter verwendet den Build-Namen als versionName und die Build-Nummer als versionCode.
Kann ich Testern stattdessen eine APK geben?
Nicht über Google Play: Neue Apps müssen als .aab hochgeladen werden, und nur Installationen aus dem geschlossenen Track zählen für die 12 Tester. flutter build apk --split-per-abi ist trotzdem praktisch für schnelle Checks auf deinen eigenen Geräten.
Warum warnt die Play Console vor 16-KB-Speicherseiten?
Meist liefert ein Plugin native .so-Bibliotheken, die nicht für 16-KB-Seiten ausgerichtet sind. Aktualisiere Plugin und Flutter, baue neu und prüfe das Ergebnis vor dem nächsten Upload auf einem Android-Emulator mit einem 16-KB-System-Image.
Quellen
Die technischen Details wurden mit der offiziellen Dokumentation unten abgeglichen. Menüs und Standardwerte ändern sich zwischen Versionen; im Zweifel gilt die offizielle Seite.
- Flutter: Build and release an Android app
- Flutter: Obfuscate Dart code
- Android Developers: Sign your app
- Android Developers: Target API level requirements
- Android Developers: Support 16 KB page sizes
- Android Developers: bundletool
- Play Console Help: App testing requirements for new personal developer accounts
- Play Console Help: Set up an open, closed, or internal test
- Play Console Help: Deobfuscate or symbolicate crash stack traces
Neu bei der Regel mit 12 Testern?
Der allgemeine Leitfaden erklärt Googles Anforderung, wie eine TestBunny-Kampagne Tag für Tag abläuft und was wir garantieren können und was nicht.
Allgemeinen Leitfaden lesen