Automating Google Play Releases with Fastlane Supply
Automating Google Play Releases with Fastlane Supply
Manually uploading an Android App Bundle (AAB) to the Google Play Console, writing release notes, attaching screenshots, and promoting builds between tracks is tedious and error-prone. Fastlane Supply automates every one of those steps from the command line — or from inside your CI pipeline — so a single command delivers a production-ready release to any Play Store track.
What Is Fastlane and Supply?
Fastlane is an open-source automation toolkit for iOS and Android. It organises automation into lanes — named sequences of actions — defined in a single Ruby file called Fastfile. Supply is the Fastlane action (and standalone tool) that talks to the Google Play Developer API: it can upload APKs/AABs, manage metadata, localised release notes, screenshots, and promote builds between tracks (internal → alpha → beta → production).
Installing Fastlane
Fastlane is a Ruby gem. Install it with Bundler (recommended) so every developer on the team uses the same version:
Install Fastlane via Bundler
# In your Flutter project root
gem install bundler
# Create a Gemfile
bundle init
# Add Fastlane to Gemfile:
# gem "fastlane"
bundle add fastlane
# Initialise Fastlane (creates android/fastlane/ directory)
cd android
bundle exec fastlane init
After initialisation you will have:
android/fastlane/Fastfile— lane definitionsandroid/fastlane/Appfile— app identifier and service-account key pathandroid/fastlane/supply/(created on firstsupply init) — metadata, changelogs, and screenshots organised by locale
Configuring the Appfile and Service Account
The Appfile tells Supply which app to manage and where to find the Google credentials:
android/fastlane/Appfile
json_key_file("fastlane/google-play-key.json") # path to service-account JSON
package_name("com.example.myapp") # your app package name
google-play-key.json to version control. Add it to .gitignore and inject it as a CI secret (environment variable or encrypted file) at build time.Writing a Deploy Lane in the Fastfile
A Fastlane lane is a Ruby method block. The deploy lane below builds the release AAB with Gradle, then calls supply to upload it to the internal track together with localised release notes:
android/fastlane/Fastfile — deploy lane
default_platform(:android)
platform :android do
desc "Build release AAB and upload to Play Store internal track"
lane :deploy do |options|
track = options[:track] || "internal" # override with: fastlane deploy track:beta
# 1. Build the signed release AAB via Gradle
gradle(
task: "bundle",
build_type: "Release",
project_dir: "../android", # path from fastlane/ to android/
print_command: false # hide the full Gradle command in logs
)
# 2. Upload AAB + release notes to the chosen track
supply(
track: track,
aab: lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH],
release_status: "draft", # "draft" | "completed" | "halted"
skip_upload_apk: true, # we are using AAB, not APK
skip_upload_images: false,
skip_upload_screenshots: false,
metadata_path: "fastlane/supply" # changelogs + store listing metadata
)
UI.success("Build uploaded to Play Store track: #{track}")
end
end
Run this lane locally with:
bundle exec fastlane deploy— uploads to the default internal trackbundle exec fastlane deploy track:beta— uploads to the beta trackbundle exec fastlane deploy track:production— uploads directly to production
Localised Release Notes and Metadata
Supply reads changelogs from the fastlane/supply/ directory. The folder structure mirrors Play Console locales:
Release notes directory layout
android/fastlane/supply/
metadata/
android/
en-US/
changelogs/
default.txt # "What's new" text for English
title.txt
short_description.txt
full_description.txt
ar/
changelogs/
default.txt # Arabic release notes
title.txt
short_description.txt
full_description.txt
images/
phoneScreenshots/ # 2-8 screenshots (PNG/JPEG, max 8 MB each)
sevenInchScreenshots/
bundle exec fastlane supply init once to pull your existing Play Store metadata into the correct folder structure. From then on, edit the text files directly and let Supply push them on the next deploy.Integrating the Lane into a CI Pipeline
The deploy lane integrates cleanly with any CI provider (GitHub Actions, Bitbucket Pipelines, GitLab CI, Codemagic). Below is a minimal GitHub Actions workflow that triggers on every push to main:
.github/workflows/deploy-android.yml
name: Deploy Android to Play Store
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Java 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.22.0"
- name: Install dependencies
run: flutter pub get
- name: Set up Ruby and Bundler
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler-cache: true
working-directory: android
- name: Decode service-account key
run: |
echo "${{ secrets.GOOGLE_PLAY_KEY_JSON }}" \
> android/fastlane/google-play-key.json
- name: Decode keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode \
> android/app/release.keystore
- name: Run Fastlane deploy lane
env:
STORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: bundle exec fastlane deploy
working-directory: android
GOOGLE_PLAY_KEY_JSON, KEYSTORE_BASE64, passwords) in your CI provider's encrypted secret store — never hard-code them in the workflow file or the Fastfile.Promoting Builds Between Tracks
Once a build passes testing on the internal track, Supply can promote it without re-uploading the AAB:
Promote lane in Fastfile
lane :promote_to_beta do
supply(
track: "internal",
track_promote_to: "beta",
skip_upload_aab: true, # no new AAB needed for promotion
skip_upload_apk: true,
skip_upload_images: true,
skip_upload_screenshots: true,
version_code: google_play_track_version_codes(track: "internal").first
)
end
Summary
Fastlane Supply removes every manual step from a Google Play release. You install Fastlane with Bundler, configure Appfile with a service-account key, define a deploy lane that calls gradle then supply, place localised release notes under fastlane/supply/metadata/, and invoke the lane from CI by injecting secrets at runtime. The result is a fully reproducible, auditable, one-command deployment pipeline that targets any Play Store track.