Skip to main content
Learn how to build release versions of your React Native app for Android distribution.

Overview

Building for Android production creates either:
  • APK (Android Package) - Direct installation file
  • AAB (Android App Bundle) - Recommended for Google Play Store

Prerequisites

1

Generate signing key

Create a keystore file for signing your app:
keytool -genkeypair -v -storetype PKCS12 \
  -keystore my-release-key.keystore \
  -alias my-key-alias \
  -keyalg RSA -keysize 2048 -validity 10000
Keep this file secure and never commit it to version control.
2

Configure signing

Edit android/gradle.properties:
android/gradle.properties
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****
Add to .gitignore:
.gitignore
# Keystore files
*.keystore
*.jks
3

Update build.gradle

Edit android/app/build.gradle:
android/app/build.gradle
android {
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file(MYAPP_RELEASE_STORE_FILE)
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias MYAPP_RELEASE_KEY_ALIAS
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
}

Building APK

Debug APK

For testing purposes:
cd android
./gradlew assembleDebug
Output: android/app/build/outputs/apk/debug/app-debug.apk

Release APK

For production distribution:
cd android
./gradlew assembleRelease
Output: android/app/build/outputs/apk/release/app-release.apk

Install APK on Device

adb install android/app/build/outputs/apk/release/app-release.apk

Building AAB (App Bundle)

Release AAB

Recommended for Google Play Store:
cd android
./gradlew bundleRelease
Output: android/app/build/outputs/bundle/release/app-release.aab
AAB files are uploaded to Google Play Store, which then generates optimized APKs for each device configuration.

Test AAB Locally

Use bundletool to test AAB files:
# Download bundletool
wget https://github.com/google/bundletool/releases/download/1.15.6/bundletool-all-1.15.6.jar

# Generate APKs from AAB
java -jar bundletool-all-1.15.6.jar build-apks \
  --bundle=android/app/build/outputs/bundle/release/app-release.aab \
  --output=app.apks \
  --ks=my-release-key.keystore \
  --ks-key-alias=my-key-alias

# Install on connected device
java -jar bundletool-all-1.15.6.jar install-apks --apks=app.apks

Build Variants

Custom Build Types

Define custom build types in android/app/build.gradle:
android/app/build.gradle
android {
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }
        staging {
            initWith debug
            applicationIdSuffix ".staging"
            matchingFallbacks = ['debug']
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
}

Build Specific Variant

cd android

# Debug
./gradlew assembleDebug

# Staging
./gradlew assembleStaging

# Release
./gradlew assembleRelease

Product Flavors

Create different app versions (e.g., free/paid):
android/app/build.gradle
android {
    flavorDimensions "version"
    productFlavors {
        free {
            dimension "version"
            applicationIdSuffix ".free"
            versionNameSuffix "-free"
        }
        paid {
            dimension "version"
            applicationIdSuffix ".paid"
            versionNameSuffix "-paid"
        }
    }
}
Build:
./gradlew assembleFreeRelease
./gradlew assemblePaidRelease

Optimization

Enable Proguard

Minify and obfuscate code in android/app/build.gradle:
android/app/build.gradle
android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

Proguard Rules

Add to android/app/proguard-rules.pro:
android/app/proguard-rules.pro
# Keep React Native classes
-keep class com.facebook.react.** { *; }
-keep class com.facebook.hermes.** { *; }

# Keep your app's classes
-keep class com.yourapp.** { *; }

# Keep native methods
-keepclasseswithmembernames class * {
    native <methods>;
}

Enable App Bundle Optimization

android/app/build.gradle
android {
    bundle {
        language {
            enableSplit = true
        }
        density {
            enableSplit = true
        }
        abi {
            enableSplit = true
        }
    }
}

Separate APKs per Architecture

android/app/build.gradle
android {
    splits {
        abi {
            enable true
            reset()
            include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
            universalApk true
        }
    }
}
This creates separate APKs:
  • app-armeabi-v7a-release.apk
  • app-arm64-v8a-release.apk
  • app-x86-release.apk
  • app-x86_64-release.apk
  • app-universal-release.apk

Version Management

Update Version

Edit android/app/build.gradle:
android/app/build.gradle
android {
    defaultConfig {
        applicationId "com.yourapp"
        versionCode 2
        versionName "1.1.0"
    }
}
  • versionCode - Integer, must increment with each release
  • versionName - String, user-facing version (e.g., “1.1.0”)

Automate Version Bumping

Use Gradle task:
android/app/build.gradle
task bumpVersion {
    doLast {
        // Custom version bumping logic
    }
}

Gradle Commands

Clean Build

cd android
./gradlew clean

Build All Variants

./gradlew build

List Tasks

./gradlew tasks

Verbose Output

./gradlew assembleRelease --info

Offline Build

./gradlew assembleRelease --offline

Continuous Integration

GitHub Actions

.github/workflows/android.yml
name: Android Build

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: npm install
      
      - name: Build AAB
        run: |
          cd android
          ./gradlew bundleRelease
      
      - name: Upload AAB
        uses: actions/upload-artifact@v3
        with:
          name: app-release.aab
          path: android/app/build/outputs/bundle/release/app-release.aab

Troubleshooting

Build Failed - Out of Memory

Error: OutOfMemoryError: Java heap space Solution: Edit android/gradle.properties:
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError

Missing Keystore

Error: Keystore file not found Solution: Ensure keystore path in gradle.properties is correct:
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
# Or absolute path
MYAPP_RELEASE_STORE_FILE=/path/to/my-release-key.keystore

Proguard Crashes App

Solution: Add keep rules for packages causing issues in proguard-rules.pro:
-keep class com.problematic.package.** { *; }

Duplicate Resources

Error: Duplicate resources Solution:
android/app/build.gradle
android {
    packagingOptions {
        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
        pickFirst 'lib/arm64-v8a/libc++_shared.so'
    }
}

Security Best Practices

  • Never commit keystores to version control
  • Use CI/CD secrets for automated builds
  • Keep separate keystores for debug and release
  • Back up keystores securely (losing them means you can’t update your app)
Use environment variables for sensitive data:
MYAPP_RELEASE_STORE_PASSWORD=$KEYSTORE_PASSWORD ./gradlew bundleRelease
Always enable code shrinking and obfuscation for release builds to protect your source code.

Next Steps

Run Android

Run and test your app on Android

Publishing Guide

Learn how to publish to Google Play Store

Android Logs

Debug with Android logs

App Signing

Complete guide to app signing

Build docs developers (and LLMs) love