Firebase App Distribution (FAD) lets you distribute pre-release APKs to testers without going through the Play Store. Combined with CI, every commit to a release branch can automatically reach testers.
Setup
# Install Firebase CLI
npm install -g firebase-tools
# Login and set project
firebase login --no-localhost # for CI: use service account
firebase use --project your-project-id
Gradle Plugin
// app/build.gradle.kts
plugins {
id("com.google.firebase.appdistribution") version "4.2.0"
}
android {
buildTypes {
release {
firebaseAppDistribution {
releaseNotes = "Build from ${System.getenv("GITHUB_SHA")?.take(7) ?: "local"}"
testers = "qa@example.com, beta@example.com"
// OR use tester groups defined in the Firebase console:
groups = "qa-team, beta-testers"
}
}
}
}
CI Workflow
# .github/workflows/beta.yml
name: Beta Distribution
on:
push:
branches: [develop] # trigger on every push to develop
jobs:
distribute:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with: { java-version: '17', distribution: 'temurin', cache: 'gradle' }
# Decode keystore from secret
- name: Decode keystore
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > app/release.keystore
# Generate release notes from git log
- name: Generate release notes
run: |
echo "RELEASE_NOTES=$(git log --oneline -5 | tr '\n' ' ')" >> $GITHUB_ENV
# Build and distribute
- name: Build & distribute
env:
KEYSTORE_PATH: release.keystore
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
./gradlew assembleStagingRelease \
appDistributionUploadStagingRelease \
-PfirebaseToken=${{ secrets.FIREBASE_TOKEN }}
Firebase Token for CI
# Generate a CI token (run locally once)
firebase login:ci
# Copy the token → add to GitHub Secrets as FIREBASE_TOKEN
Alternatively use a service account JSON:
- name: Authenticate to Firebase
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}
- name: Distribute
run: ./gradlew appDistributionUploadStagingRelease
Tester Groups in Firebase Console
Firebase Console → App Distribution → Testers & Groups
- "qa-team": QA engineers (5–10 people)
- "beta-testers": External beta users (up to hundreds)
- "executives": Leadership stakeholders
Each group gets an email with a download link. FAD manages device registration automatically.
Release Notes Best Practices
// Automate release notes from git
firebaseAppDistribution {
releaseNotesFile = "${project.rootDir}/release-notes.txt"
}
# In CI, generate release-notes.txt before Gradle task
git log origin/main..HEAD --pretty=format:"- %s" > release-notes.txt
Compare with TestFlight / Play Internal Track
| Feature | Firebase App Distribution | Play Internal Testing | TestFlight |
|---|---|---|---|
| Platforms | Android + iOS | Android | iOS |
| Max testers | Unlimited | 100 | 10,000 |
| Store review | No | No | No |
| Side-load | Yes (via FAD app) | Via Play Store | Via TestFlight |
| Price | Free | Free | Free |
| CI integration | Gradle plugin / CLI | Google Play API | Fastlane / Xcode |
Key Takeaways
| Practice | Rule |
|---|---|
Trigger on develop push | Automatic tester delivery on every merge |
| Release notes from git | git log --oneline → paste to FAD; useful for QA triage |
| Service account for CI | More secure than personal firebase login:ci token |
| Tester groups | Separate QA / beta / execs; not everyone gets every build |
| FAD + Play Internal | Use FAD for pre-QA builds; move to Play Internal Track for final beta |