🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)
🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)

🔧 Programmierung 🕛 vor 2 Monaten 8 Min Lesezeit
0

Automating Flutter Android Releases to Google Play using GitHub Actions

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Publishing a Flutter app manually is fine once.



Doing it every time by downloading an .aab, opening Play Console, uploading it, checking versions, and creating releases manually is trash. It is slow, error-prone, and sooner or later you will upload the wrong build.



In this article, I’ll document the complete end-to-end flow to publish a Flutter Android app to Google Play using GitHub Actions.









Final Release Flow






CODE
feature/*


develop


Flutter CI

────────────────────────────

main


Flutter CI


Internal Release


Google Play Internal Testing

────────────────────────────

git tag v1.0.0


Production Release


Google Play Production


GitHub Release












Part 1: Google Play Console Setup



Before GitHub Actions can upload builds to Google Play, Google Play must trust a service account.



The flow is:




CODE
Google Play Console

Google Cloud Project

Enable Google Play Android Developer API

Create Service Account

Create JSON Key

Invite Service Account in Play Console

Grant Release Permissions

Store JSON in GitHub Environment Secret












Step 1: Create App in Google Play Console



Go to Google Play Console and create your app.



You need to configure:




  • App name

  • Default language

  • App type

  • Free or paid

  • Declarations

  • Privacy Policy

  • App access

  • Ads declaration

  • Data safety

  • Content rating

  • Target audience

  • Store listing



Do not automate this part first. Get your Play Console app created manually before setting up CI/CD.









Step 2: Link Google Play Console with Google Cloud Project



Go to:




CODE
Google Play Console
→ Setup
→ API access






Create or link a Google Cloud Project.



This project will be used to create the service account that GitHub Actions will use.









Step 3: Enable Google Play Android Developer API



In Google Cloud Console:




CODE
APIs & Services
→ Library
→ Google Play Android Developer API
→ Enable






Without this API, your GitHub workflow cannot upload Android App Bundles to Play Console.









Step 4: Create Service Account



In Google Cloud Console:




CODE
IAM & Admin
→ Service Accounts
→ Create Service Account






Example name:




CODE
github-actions-playstore-release






After creating it, copy the service account email.



It will look like this:




CODE
github-actions-playstore-release@your-project-id.iam.gserviceaccount.com












Step 5: Create JSON Key



Open the created service account.



Go to:




CODE
Keys
→ Add Key
→ Create New Key
→ JSON






Download the JSON file.



Important:



Never commit this JSON file.



If you commit this file, your release pipeline is compromised. Delete the key immediately and create a new one.









Step 6: Invite Service Account in Play Console



Go back to Play Console:




CODE
Users and permissions
→ Invite new users






Paste the service account email.



Grant app-level access to your app.



Recommended permissions:




CODE
View app information
Create and edit draft apps
Release to testing tracks
Release to production
Manage testing tracks






For internal release only, production permission is not required.



For production workflow, production release permission is required.









Part 2: GitHub Secrets Setup



Use GitHub Environment Secrets, not plain repository secrets.



Create environments:




CODE
internal
production






Go to:




CODE
GitHub Repository
→ Settings
→ Environments
→ internal
→ Environment secrets






Add:




CODE
PLAY_STORE_SERVICE_ACCOUNT_JSON






Paste the full JSON content from the service account key.



For production, repeat the same under:




CODE
production






Also add signing secrets:




CODE
ANDROID_KEYSTORE_BASE64
ANDROID_KEYSTORE_PASSWORD
ANDROID_KEY_ALIAS
ANDROID_KEY_PASSWORD












Part 3: Flutter Android Signing Setup



Your Flutter app must generate a signed Android App Bundle.



Create:




CODE
android/key.properties






Do not commit the real file.



Example:




CODE
storePassword=your_store_password
keyPassword=your_key_password
keyAlias=upload
storeFile=upload-keystore.jks






In CI, GitHub Actions will recreate this file from secrets.



Also make sure your android/app/build.gradle is configured for release signing.









Part 4: Flutter CI Workflow



This workflow runs for feature branches, develop, and main.



File:




CODE
.github/workflows/flutter-ci.yml









CODE
name: Flutter CI

on:
pull_request:
branches:
- develop
- main

push:
branches:
- develop
- main
- "feature/**"

permissions:
contents: read

jobs:
flutter-ci:
name: Flutter Analyze & Test
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Flutter
uses: ./.github/actions/setup-flutter

- name: Install Dependencies
run: flutter pub get

- name: Analyze
run: flutter analyze

- name: Run Tests
run: flutter test






This is your quality gate.



If this fails, no release should happen.









Part 5: Internal Release Workflow



This workflow runs after Flutter CI succeeds on main.



File:




CODE
.github/workflows/internal-release.yml









CODE
name: Internal Release

on:
workflow_run:
workflows:
- Flutter CI
types:
- completed

permissions:
contents: read

concurrency:
group: internal-release-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true

jobs:
build-and-deploy:
name: Build & Deploy Internal Release
runs-on: ubuntu-latest
timeout-minutes: 35
environment: internal

if: >
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main'

steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch }}
fetch-depth: 0

- name: Setup Flutter
uses: ./.github/actions/setup-flutter

- name: Restore Android Keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/upload-keystore.jks

- name: Create key.properties
run: |
cat > android/key.properties <<EOF
storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
storeFile=upload-keystore.jks
EOF

- name: Create Play Store Service Account JSON
run: |
echo '${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}' > play-store-service-account.json

- name: Install Dependencies
run: flutter pub get

- name: Build Android App Bundle
run: flutter build appbundle --release

- name: Upload to Play Store Internal Testing
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJson: play-store-service-account.json
packageName: com.yourcompany.yourapp
releaseFiles: build/app/outputs/bundle/release/app-release.aab
track: internal
status: completed






Replace:




CODE
com.yourcompany.yourapp






with your actual Android package name.









Part 6: Production Release Workflow



Production releases should not happen on every merge.



That is reckless.



Use Git tags.



Example:




CODE
git tag v1.0.0
git push origin v1.0.0






File:




CODE
.github/workflows/production-release.yml









CODE
name: Production Release

on:
push:
tags:
- "v*.*.*"

permissions:
contents: write

concurrency:
group: production-release
cancel-in-progress: false

jobs:
production-release:
name: Build & Deploy Production Release
runs-on: ubuntu-latest
timeout-minutes: 45
environment: production

steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Flutter
uses: ./.github/actions/setup-flutter

- name: Restore Android Keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/upload-keystore.jks

- name: Create key.properties
run: |
cat > android/key.properties <<EOF
storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
storeFile=upload-keystore.jks
EOF

- name: Create Play Store Service Account JSON
run: |
echo '${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}' > play-store-service-account.json

- name: Install Dependencies
run: flutter pub get

- name: Build Android App Bundle
run: flutter build appbundle --release

- name: Upload to Play Store Production
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJson: play-store-service-account.json
packageName: com.yourcompany.yourapp
releaseFiles: build/app/outputs/bundle/release/app-release.aab
track: production
status: completed

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: build/app/outputs/bundle/release/app-release.aab












Part 7: Versioning



Flutter uses version from pubspec.yaml.



Example:




CODE
version: 1.0.0+1






Format:




CODE
versionName+versionCode






Example:




CODE
1.0.0+1






Means:




CODE
versionName = 1.0.0
versionCode = 1






Every Play Store upload must have a higher versionCode.



If you upload the same version code again, Play Console will reject it.



For next release:




CODE
version: 1.0.1+2












Part 8: Recommended Branch Strategy



Use this:




CODE
feature/*  → development work
develop → integration branch
main → release-ready branch
tag → production release






Flow:




CODE
feature/login-screen

develop

main

internal testing

tag v1.0.0

production






Do not release production directly from a random feature branch.



That is not CI/CD. That is gambling.









Part 9: Required GitHub Environments



Create these environments:




CODE
internal
production






Recommended protection:



For internal:




CODE
No manual approval required






For production:




CODE
Required reviewers enabled






This means production release waits for approval before uploading to Google Play.









Part 10: Common Mistakes






Mistake 1: Service account created but not invited to Play Console



Creating a service account in Google Cloud is not enough.



You must invite the service account email in Play Console.









Mistake 2: Missing release permissions



If the service account does not have release permissions, upload will fail.



Grant only the permissions required for that environment.



Internal environment should not need production release access.









Mistake 3: Committing the JSON key



Never commit:




CODE
play-store-service-account.json
upload-keystore.jks
key.properties






Add them to .gitignore.




CODE
android/key.properties
android/app/upload-keystore.jks
play-store-service-account.json












Mistake 4: Reusing same versionCode



Play Console requires every uploaded app bundle to have a higher version code.



Bad:




CODE
version: 1.0.0+1






again and again.



Good:




CODE
version: 1.0.0+1
version: 1.0.1+2
version: 1.0.2+3












Mistake 5: Production release on every main merge



Main branch should trigger internal testing.



Production should trigger only from tags.



That gives you control.









Final Flow






CODE
Developer pushes feature branch

Pull request to develop

Flutter CI runs

Merge develop to main

Flutter CI runs

Internal release workflow uploads AAB to Play Store Internal Testing

Testers verify app

Create git tag v1.0.0

Production release workflow uploads AAB to Play Store Production

GitHub Release is created












Conclusion



This setup gives a clean Flutter Android release pipeline:




  • Feature branches only run CI


  • develop validates integration


  • main publishes to Internal Testing

  • Git tags publish to Production

  • Service account handles Play Store upload

  • GitHub Environment Secrets protect credentials

  • Production can be protected with manual approval



Manual Play Store uploads are fine for the first release.



After that, automate it.



Otherwise, your release process will eventually break at the worst possible time.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Sam Altman calls GPT-6 Astra rollout ‘messy’ as enterprise users wait for access
1 Quelle
Swiss government explores replacing Microsoft 365 with open-source software
1 Quelle
What continuous operational resilience looks like under DORA
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Automating Flutter Android Releases to Google Play using GitHub Actions

Thematisch verwandte Begriffe: Automating, Flutter, Android, Releases · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...