Back to Journal
Development
May 18, 2026
15 min read

CI/CD Tutorial: Fastlane + GitHub Actions for Flutter Android

A
Arumi Dev Team
Flutter Developers
CI/CD Tutorial: Fastlane + GitHub Actions for Flutter Android

Overview

The pipeline does the following on every manual trigger:

  1. Decodes secrets (keystore, service account) from GitHub Secrets
  2. Sets up Java, Flutter, and Ruby environments
  3. Runs Fastlane to auto-increment the build number, build the AAB + APK, and upload to Play Store (internal track)
  4. Uploads artifacts to GitHub Actions
  5. Creates a GitHub Release with the AAB and APK attached

Prerequisites

  • A Flutter Android project
  • A Google Play Console account with your app created (at least one manual upload done)
  • A Google Cloud Platform (GCP) project
  • A signing keystore for your Android app
  • Ruby installed locally (for running fastlane init)

Step 1: Create a Keystore for App Signing

If you don't already have a keystore, generate one:

keytool -genkey -v -keystore release-keystore.jks -alias your-key-alias -keyalg RSA -keysize 2048 -validity 10000

Keep note of:

  • storePassword — the keystore password
  • keyPassword — the key password
  • keyAlias — the alias you chose

Do not commit the .jks file. Add it to .gitignore.

Step 2: Configure key.properties in Android

Create android/key.properties (also add to .gitignore):

storePassword=YOUR_STORE_PASSWORD keyPassword=YOUR_KEY_PASSWORD keyAlias=YOUR_KEY_ALIAS storeFile=release-keystore.jks

In android/app/build.gradle.kts, load and use this file for signing:

val keystorePropertiesFile = rootProject.file("key.properties") val keystoreProperties = Properties() if (keystorePropertiesFile.exists()) { keystoreProperties.load(FileInputStream(keystorePropertiesFile)) }

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") } }

Step 3: Set Up GCP Service Account

Fastlane uses a Google Play API service account to upload builds.

  1. Go to Google Cloud Console
  2. Create a new project (or use an existing one)
  3. Enable the Google Play Android Developer API
  4. Go to IAM & Admin → Service Accounts → Create Service Account
  5. Give it a name (e.g., fastlane-cicd)
  6. Grant it no roles at the project level
  7. Create and download a JSON key for this service account

Grant Access in Play Console

  1. Open Google Play Console
  2. Go to Setup → API access
  3. Link to the GCP project you created
  4. Find your service account, click Grant Access
  5. Assign the Release Manager role

Step 4: Initialize Fastlane

From the android/ directory:

cd android fastlane init

When prompted, choose Google Play as the deployment target and provide your package name.

This generates:

  • android/Gemfile
  • android/fastlane/Appfile
  • android/fastlane/Fastfile

Step 5: Configure Fastlane Files

android/Gemfile

source "https://rubygems.org" gem "fastlane"

android/fastlane/Appfile

json_key_file("~/fastlane/service_account.json") package_name("com.example.yourapp")

android/fastlane/Fastfile

Fastlane automatically:

  • Fetches the highest version code across all tracks
  • Increments build number automatically
  • Builds APK and AAB files
  • Uploads to internal testing track
  • Writes build_number.txt for GitHub Releases

Key points:

  • No manual version bumping needed
  • Internal track upload by default
  • Faster uploads by skipping metadata/images/screenshots

Step 6: Add GitHub Secrets

Go to GitHub → Settings → Secrets and variables → Actions.

Add:

  • ANDROID_KEYSTORE
  • SERVICE_ACCOUNT
  • KEYSTORE_PASSWORD
  • KEY_PASSWORD
  • KEY_ALIAS

Use Base64 encoding for keystore and service account files.

Step 7: GitHub Actions Workflow

Create .github/workflows/deploy_android.yml.

The workflow:

  • Checks out repository
  • Sets up Java, Flutter, and Ruby
  • Decodes secrets
  • Runs Fastlane deploy
  • Uploads APK/AAB artifacts
  • Creates GitHub Release automatically

Notable Decisions

  • workflow_dispatch allows manual release triggering
  • continue-on-error keeps artifact upload running even if Play Store upload fails
  • permissions: contents: write is required for GitHub Releases
  • working-directory: android ensures Fastlane runs correctly

File Structure Summary

project-root/ ├── .github/ │ └── workflows/ │ └── deploy_android.yml ├── android/ │ ├── Gemfile │ ├── Gemfile.lock │ ├── key.properties │ ├── app/ │ │ ├── build.gradle.kts │ │ └── release-keystore.jks │ └── fastlane/ │ ├── Appfile │ └── Fastfile └── pubspec.yaml

Triggering a Release

  1. Go to GitHub Actions
  2. Select Deploy Flutter Android
  3. Click Run workflow

The pipeline will:

  • Auto-detect next versionCode
  • Build APK and AAB
  • Upload to Play Store internal track
  • Create GitHub Release

Supply (upload_to_play_store) Reference

Available tracks:

  • internal
  • alpha
  • beta
  • production

Key parameters:

  • track
  • aab
  • rollout
  • release_status
  • track_promote_to

Fastlane also supports:

  • Gradual rollouts
  • Track promotion
  • Metadata downloads
  • Screenshot management

Important: First Upload Must Be Manual

The Play Store API cannot push to an app that has never had a build uploaded manually through Play Console.

Common Issues

Google Api Error

Only releases with status draft may be created on draft app.

Solution: Complete at least one manual Play Store upload first.

Version code already exists

Re-run the workflow to get a fresh build number.

base64: invalid input

Encode files without line breaks:

  • Linux: base64 -w 0 file
  • macOS: base64 -i file

Conclusion

Using Fastlane with GitHub Actions creates a powerful CI/CD pipeline for Flutter Android apps. It automates versioning, building, Play Store deployment, artifact uploads, and GitHub Releases while reducing manual work and deployment errors.

#Flutter#CI/CD#Fastlane#GitHub Actions#Android#DevOps