Google Play Store & Publishing
Building the app is half the job. Getting it into users' hands — and getting paid — is the other half. This module covers the entire publishing pipeline from your first signing key to your first paying customer.
Topic 1 · Publishing
Play Console setup & app signing
Create a developer account at play.google.com/console ($25 one-time fee). Create your app entry, fill out store listing, content rating, target audience, data safety, and privacy policy URL.
Play App Signing is mandatory: you upload an App Bundle signed with an upload key, and Google re-signs the artifacts that ship to users with the app signing key (which Google holds securely on your behalf).
# Generate an upload keystore (do this ONCE; back it up safely)
keytool -genkey -v \
-keystore upload-keystore.jks \
-keyalg RSA -keysize 2048 -validity 10000 \
-alias upload
Configure signing in Gradle (load from ~/.gradle/gradle.properties, never commit credentials):
// app/build.gradle.kts
android {
signingConfigs {
create("release") {
storeFile = file(System.getenv("UPLOAD_KEYSTORE_PATH") ?: "upload-keystore.jks")
storePassword = System.getenv("UPLOAD_STORE_PASSWORD")
keyAlias = System.getenv("UPLOAD_KEY_ALIAS")
keyPassword = System.getenv("UPLOAD_KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
isShrinkResources = true
}
}
}
Building the App Bundle
Android App Bundles (.aab) ship the universal artifact to Google Play; Play generates per-device APKs, reducing download size by 15–25%.
# Local build
./gradlew bundleRelease
# Output
app/build/outputs/bundle/release/app-release.aab
Upload the .aab to a release track (Internal → Closed → Open → Production).
Use Internal Testing for your team, Closed Testing for beta groups,
Open Testing for public betas.
Release tracks & staged rollouts
| Track | Audience | Use for |
|---|---|---|
| Internal | Up to 100 testers via email | Daily smoke tests |
| Closed | Email lists or Google groups | Beta partners, regulated testing |
| Open | Anyone with the testing URL | Public betas |
| Production | Everyone — staged rollouts available | Live releases |
Always use staged rollout for production (e.g., 1% → 5% → 20% → 50% → 100% over 5–7 days). Watch Crashlytics during each phase and halt the rollout if you see new crash spikes.
Topic 2 · Monetization
In-app purchases & subscriptions
Use the Google Play Billing Library 7+. It supports one-time purchases (consumable & non-consumable) and subscriptions with offers, upgrades, and free trials.
// 1. Connect to Play Billing
val billingClient = BillingClient.newBuilder(ctx)
.setListener { result, purchases -> /* handle results */ }
.enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(result: BillingResult) { /* ready */ }
override fun onBillingServiceDisconnected() { /* reconnect */ }
})
// 2. Query products
val params = QueryProductDetailsParams.newBuilder()
.setProductList(listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("pro_subscription")
.setProductType(BillingClient.ProductType.SUBS)
.build()
))
.build()
val (result, products) = billingClient.queryProductDetails(params)
// 3. Launch purchase flow
val flowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(listOf(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(products!!.first())
.setOfferToken(products.first().subscriptionOfferDetails?.firstOrNull()?.offerToken!!)
.build()
))
.build()
billingClient.launchBillingFlow(activity, flowParams)
Ad monetization with AdMob
For ad-supported apps, integrate Google Mobile Ads SDK. Three primary ad formats:
| Format | Best for |
|---|---|
| Banner | Persistent low-intrusion (small bottom strip) |
| Interstitial | Natural break points (level end, screen transition) |
| Rewarded | Optional value exchange (extra lives, hint, premium content) |
Show ads sparingly. Two interstitials in a five-minute session destroys retention faster than zero ads.
App Store Optimization (ASO)
ASO is SEO for the Play Store. The factors that matter:
Title & short description
Include 1–2 high-volume keywords; first 80 characters of description matter most.
Icon, screenshots, video
A great icon raises CTR 30%+. Screenshots tell the story; the first three are most viewed.
Ratings & reviews
Above 4.4 ★ unlocks featured placements. Use the in-app review API at the right moment.
Install speed & retention
Play's ranking model rewards apps users keep open. Optimize startup and onboarding.
Localization
Localize at least the title, description, and screenshots for your top 5 markets.
A/B testing
Use Play Console Store Listing Experiments to test icon/screenshot/description variants.
// In-app review prompt — choose a moment of high satisfaction
val reviewManager = ReviewManagerFactory.create(ctx)
val flow = reviewManager.requestReviewFlow().await()
reviewManager.launchReviewFlow(activity, flow).await()
Pre-launch checklist
Must-have
- Privacy policy URL filled in
- Data safety form completed accurately
- Target API level meets Play requirements
- App signing via Play App Signing enabled
- ProGuard / R8 enabled and tested
- Crashlytics + Analytics live
Often missed
- Permission rationale strings localized
- Backup rules (no secrets in backup)
- Network security config (no cleartext)
- Adaptive icon variants
- App Bundle device targeting checked
- Phased rollout configured
Key takeaways
Practice exercises
- 01
Build & sign a release bundle
Generate an upload keystore, configure signing in Gradle, and produce app-release.aab.
- 02
In-app review
Show the in-app review prompt after a user completes their third successful action.
- 03
ASO audit
Take a real public app on Play Store and write a critique of its title, icon, screenshots, and description.
Next module
Continue to Module 12 — Advanced & Trending Topics for KMP, ML Kit, Wear OS, BLE, and more.