androidengineers.Book a session

CI/CD Pipeline

Beta Distribution (Firebase App Dist.)

article20 minMedium

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

FeatureFirebase App DistributionPlay Internal TestingTestFlight
PlatformsAndroid + iOSAndroidiOS
Max testersUnlimited10010,000
Store reviewNoNoNo
Side-loadYes (via FAD app)Via Play StoreVia TestFlight
PriceFreeFreeFree
CI integrationGradle plugin / CLIGoogle Play APIFastlane / Xcode

Key Takeaways

PracticeRule
Trigger on develop pushAutomatic tester delivery on every merge
Release notes from gitgit log --oneline → paste to FAD; useful for QA triage
Service account for CIMore secure than personal firebase login:ci token
Tester groupsSeparate QA / beta / execs; not everyone gets every build
FAD + Play InternalUse FAD for pre-QA builds; move to Play Internal Track for final beta

YOUR LEARNING JOURNEY

0 of 177 available lessons completed

Progress saved in this browser. No account needed.
Beta Distribution (Firebase App Dist.) | Android System Design | Android Engineers