← Back to Tutorials Chapter 16

Deployment

Preparing for Release

App Signing

// Generate a signing key
// Android Studio: Build > Generate Signed Bundle / APK

// Or via command line:
keytool -genkey -v -keystore my-release-key.jks \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -alias my-alias

// app/build.gradle.kts
android {
    signingConfigs {
        create("release") {
            storeFile = file("my-release-key.jks")
            storePassword = "password"
            keyAlias = "my-alias"
            keyPassword = "password"
        }
    }
    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("release")
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

App Bundles vs APK

Google Play requires Android App Bundles (AAB) for new apps. App Bundles allow Google Play to generate optimized APKs for different device configurations.

# Generate App Bundle
./gradlew bundleRelease

# Located at: app/build/outputs/bundle/release/app-release.aab

# Generate APK (alternative)
./gradlew assembleRelease

# Test the bundle using bundletool
java -jar bundletool.jar build-apks \
  --bundle=app-release.aab \
  --output=app-release.apks \
  --ks=my-release-key.jks \
  --ks-pass=pass:password \
  --ks-key-alias=my-alias

# Install on device
java -jar bundletool.jar install-apks --apks=app-release.apks

Google Play Console

Versioning Strategy

// app/build.gradle.kts
android {
    defaultConfig {
        applicationId = "com.example.myapp"
        minSdk = 24
        targetSdk = 34

        // Increment versionCode for each release
        versionCode = 5
        versionName = "2.1.0"
    }
}

// Semantic versioning: MAJOR.MINOR.PATCH
// - MAJOR: Breaking changes
// - MINOR: New features (backward compatible)
// - PATCH: Bug fixes

// versionCode vs versionName
// versionCode: Integer, must increment for each update
// versionName: Human-readable version string

Crash Reporting

// Firebase Crashlytics
// build.gradle.kts
// implementation("com.google.firebase:firebase-crashlytics")

// Initialize in Application class
FirebaseCrashlytics.getInstance().apply {
    setCrashlyticsCollectionEnabled(true)
    log("App started")
    setUserId("user_123")
}

// Log custom events
FirebaseCrashlytics.getInstance().recordException(Exception("Payment failed"))

// Firebase Performance Monitoring
// implementation("com.google.firebase:firebase-perf")
// Automatically monitors app startup, network, and screen rendering

CI/CD for Android

# .github/workflows/android-ci.yml
name: Android CI

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: 17
      - run: ./gradlew test

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: 17
      - run: ./gradlew bundleRelease
      - uses: actions/upload-artifact@v4
        with:
          name: app-bundle
          path: app/build/outputs/bundle/release/app-release.aab
Exercise: Prepare an app for release on Google Play. Generate a signing key, configure the build.gradle.kts for release with ProGuard, create an Android App Bundle, and verify it works by testing via bundletool on a physical device or emulator.