Android deployment has its own class of surprises — keystore files that get lost and brick your app's update capability, AAB vs APK confusion, Play App Signing opt-in that cannot be undone, and policy violations that trigger account suspensions with little explanation. After shipping numerous React Native apps through Play Console, I've documented the exact steps and failure modes so you don't repeat them.
Step 1 — Create a Google Play Developer account
Go to play.google.com/console and pay the one-time $25 registration fee using a Google account. Use a dedicated Google account for company apps — not your personal Gmail. If registering as an organisation, you will need to verify your developer identity with a government-issued ID or business documents (introduced in 2023 as part of Google's developer verification program). This verification can take 2–7 business days. Your Play Console account is permanent — do not delete it as it cannot be transferred to another Google account.
Step 2 — Generate a release keystore
Your release keystore is the cryptographic identity of your app. Google uses it to verify that updates come from the same developer as the original release. If you lose this file and its password, you can never push updates to that app listing — you would have to publish an entirely new app with a new package name and lose all reviews, ratings, and install history. Back this file up in multiple secure locations immediately after creating it.
# Run from your project root — replace ALL placeholder values keytool -genkeypair -v \ -storetype PKCS12 \ -keystore android/app/release.keystore \ -alias your-key-alias \ -keyalg RSA \ -keysize 2048 \ -validity 10000 # You will be prompted for: # - Keystore password (store this securely) # - Key password (can be same as keystore password) # - Your name, organisation, city, state, country code # IMMEDIATELY back up release.keystore to a password manager or secure cloud storage # Add to .gitignore — never commit your keystore to version control
Step 3 — Configure Gradle signing
# Add to gradle.properties (this file is in .gitignore by default) MYAPP_UPLOAD_STORE_FILE=release.keystore MYAPP_UPLOAD_KEY_ALIAS=your-key-alias MYAPP_UPLOAD_STORE_PASSWORD=your-keystore-password MYAPP_UPLOAD_KEY_PASSWORD=your-key-password
android {
...
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
release {
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
storeFile file(MYAPP_UPLOAD_STORE_FILE)
storePassword MYAPP_UPLOAD_STORE_PASSWORD
keyAlias MYAPP_UPLOAD_KEY_ALIAS
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
}
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true // enables ProGuard/R8
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}Step 4 — Build the release AAB in Android Studio
Google Play requires Android App Bundle (AAB) format since August 2021 — APKs are no longer accepted for new apps. AAB lets Play generate optimised APKs per device configuration (screen density, CPU architecture), reducing install size by 15–40% compared to a universal APK. In Android Studio: Build → Generate Signed Bundle / APK → Android App Bundle → select your keystore and fill in the credentials → choose release build variant → Finish. The output .aab file will be in android/app/release/.
# From project root — build release AAB without opening Android Studio cd android && ./gradlew bundleRelease # Output: android/app/build/outputs/bundle/release/app-release.aab # Verify the bundle with bundletool (optional but recommended) java -jar bundletool.jar build-apks \ --bundle=app-release.aab \ --output=app.apks \ --ks=app/release.keystore \ --ks-key-alias=your-key-alias \ --ks-pass=pass:your-keystore-password
Step 5 — Play Console app setup
In Play Console, click Create app — choose app or game, free or paid, and confirm policy declarations. Fill in the store listing: title (30 chars), short description (80 chars), full description (4000 chars), and upload graphics. Required assets: feature graphic (1024×500px), at least 2 screenshots per form factor you support (phone mandatory, tablet if applicable), and a high-res icon (512×512px PNG). The feature graphic appears as a banner when your app is featured — make it visually compelling even if you never get featured.
Step 6 — Play App Signing (mandatory for AAB)
When uploading your first AAB, Play Console will prompt you to opt into Play App Signing. This is now mandatory for all new apps. Google stores and manages the final signing key used to sign APKs delivered to users. You upload with your upload key (the keystore you generated), Google re-signs with their app signing key before delivery. The critical implication: your upload keystore password is now only needed for uploads — if you lose it, Google can reset your upload key via identity verification. Register your upload key's SHA-1 and SHA-256 in Firebase to keep Google Sign In working.
Step 7 — Release tracks
Play Console has four release tracks: Internal Testing (up to 100 testers, instant publish, no review, use this for daily builds), Closed Testing / Alpha (specific tester groups, no review, takes ~hours), Open Testing / Beta (public opt-in, no review, good for stress testing), and Production (full rollout or staged, requires Google review for new apps — typically 1–3 days). Always start with Internal Testing to verify the AAB installs correctly on real devices before pushing to Production. Use staged rollout (start at 10–20%) for production releases to catch crashes before they hit all users.
# build.gradle — automate deployments with gradle-play-publisher
plugins {
id 'com.github.triplet.play' version '3.8.4'
}
play {
serviceAccountCredentials.set(file('play-service-account.json'))
track.set('internal') // or 'alpha', 'beta', 'production'
userFraction.set(0.1) // 10% staged rollout
updatePriority.set(2) // 0-5, used by Play Core for in-app updates
defaultToAppBundles.set(true)
}
// Then run: ./gradlew publishReleaseBundleStep 8 — Content rating, target audience, and data safety
Play Console requires three declarations before you can publish: Content Rating (complete the IARC questionnaire — takes 5 minutes, assigns age ratings for all regions automatically), Target Audience and Content (specify minimum age, whether the app targets children — if yes, additional COPPA compliance requirements apply), and Data Safety section (mandatory since 2022 — declare every data type your app collects, whether it's shared with third parties, and whether users can request deletion). The data safety form must match your privacy policy. Inconsistencies between the two are a policy violation and can cause suspension.
ProGuard and common release build crashes
minifyEnabled true turns on R8 code shrinking which renames classes — this breaks reflection-based libraries and causes crashes in release that never appear in debug. Add keep rules to proguard-rules.pro for any library that uses reflection: Gson models, Retrofit interfaces, React Native native modules. If you get a ClassNotFoundException in release, the class was shrunk away. Check the R8 mapping file at android/app/build/outputs/mapping/release/mapping.txt to trace obfuscated stack traces back to readable class names — upload this file to Play Console's Android Vitals for automatic deobfuscation in crash reports.
# Keep React Native
-keep class com.facebook.react.** { *; }
-keep class com.facebook.hermes.** { *; }
-keep class com.facebook.jni.** { *; }
# Keep your app's native modules
-keep class com.yourcompany.yourapp.** { *; }
# Keep Gson models (if using Gson)
-keepattributes Signature
-keepattributes *Annotation*
-dontwarn sun.misc.**
-keep class com.google.gson.** { *; }
# Keep OkHttp (used by many RN libraries)
-dontwarn okhttp3.**
-dontwarn okio.**Critical checklist before first Play Store submission: back up your release keystore in at least 2 separate secure locations, opt into Play App Signing and save your upload key certificate, complete the Data Safety form honestly (mismatches with your privacy policy cause suspensions), test the exact release AAB via Internal Testing on 2–3 physical devices before promoting to Production, and upload your ProGuard mapping.txt to Android Vitals so crash reports are readable.