This is it — the final tutorial.
You built a complete task manager app with Jetpack Compose, Room, Hilt, Navigation, MVI, animations, and adaptive layouts. Now let’s put it in the hands of real users.
Before You Publish — Checklist
Make sure your app is ready:
- App works — test every feature on a real device
- No crashes — check Logcat for errors
- Dark mode works — test both themes
- Different screen sizes — test on phone and tablet
- Keyboard handling — forms work with keyboard visible
- Proguard/R8 — release build compiles and runs
- App icon — custom icon (not the default green Android)
- App name — set in
strings.xml
Step 1: Generate a Signing Key
Every app on Google Play must be signed. This proves the app comes from you.
Using Android Studio
- Build → Generate Signed Bundle/APK
- Click Create new… under Key store path
- Fill in:
- Key store path:
/path/to/your-keystore.jks - Password: (choose a strong password)
- Alias:
release - Key password: (can be same as store password)
- Validity: 25 years
- First and Last name: your name
- Key store path:
- Click OK
Using Command Line
keytool -genkey -v \
-keystore release-keystore.jks \
-keyalg RSA \
-keysize 2048 \
-validity 9125 \
-alias release
CRITICAL: Back up your keystore file and passwords. If you lose them, you can never update your app. Store them in a password manager.
Step 2: Configure Signing in Gradle
Create a keystore.properties file in your project root (add to .gitignore!):
# keystore.properties — NEVER commit this file
storeFile=../release-keystore.jks
storePassword=your_store_password
keyAlias=release
keyPassword=your_key_password
Update app/build.gradle.kts:
// Load keystore properties
val keystoreProperties = Properties()
val keystoreFile = rootProject.file("keystore.properties")
if (keystoreFile.exists()) {
keystoreProperties.load(keystoreFile.inputStream())
}
android {
signingConfigs {
create("release") {
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
}
}
buildTypes {
release {
isMinifyEnabled = true // Shrink and optimize
isShrinkResources = true // Remove unused resources
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("release")
}
}
}
Add to .gitignore:
keystore.properties
*.jks
Step 3: Build the Release AAB
Google Play requires AAB (Android App Bundle), not APK:
./gradlew bundleRelease
The AAB file is at: app/build/outputs/bundle/release/app-release.aab
Test the Release Build
# Build and install the release version
./gradlew installRelease
# Or build an APK for testing
./gradlew assembleRelease
Test the release build on a real device. Make sure:
- Proguard didn’t break anything
- All features work
- Performance is good
Step 4: Create Your Google Play Developer Account
- Go to play.google.com/console
- Pay the one-time $25 registration fee
- Verify your identity (takes 1-3 business days)
- Accept the Developer Distribution Agreement
Step 5: Create the App Listing
In the Play Console:
App Details
| Field | What to Write |
|---|---|
| App name | Task Manager (or your app’s name) |
| Short description | Under 80 chars — “Simple task manager with categories, priorities, and dark mode” |
| Full description | 500-4000 chars — describe all features, use bullet points |
Graphics
| Graphic | Requirements |
|---|---|
| App icon | 512x512 PNG (no transparency) |
| Feature graphic | 1024x500 PNG (shown at top of listing) |
| Screenshots | Min 2, max 8. Phone: 1080x1920 or 1920x1080 |
| Tablet screenshots | Recommended. 1200x1920 or 1920x1200 |
Taking Good Screenshots
# Take a screenshot from the emulator
adb exec-out screencap -p > screenshot_1.png
# Take on a specific resolution for Play Store
# Use a Pixel 6 emulator (1080x2400) for phone shots
# Use a Pixel Tablet emulator for tablet shots
Tips for screenshots:
- Show the app in action (not empty states)
- Show different features in different screenshots
- Include both light and dark mode shots
- Add text overlays describing features (use Figma or Canva)
Content Rating
Fill out the content rating questionnaire. For a task manager:
- No violence, no gambling, no adult content
- Result: typically Everyone rating
Privacy Policy
Required for all apps. Create a simple privacy policy:
Your app name does not collect any personal data.
All tasks are stored locally on your device.
No data is sent to external servers.
Host it as a page on your website or use a free privacy policy generator.
Step 6: Upload the AAB
- In Play Console → Production → Create new release
- Upload your
app-release.aabfile - Add release notes: “Initial release — task manager with categories, priorities, search, and dark mode”
- Click Review release
- Click Start rollout to Production
Review Process
Google reviews your app. This takes 1-7 days for new apps. They check for:
- Policy violations (content, permissions, data collection)
- Technical issues (crashes, ANR)
- Metadata accuracy (screenshots match the app)
Step 7: After Publishing
Monitor Your App
In Play Console:
- Crashes & ANRs — check daily for the first week
- Reviews — respond to user feedback
- Statistics — track installs, uninstalls, ratings
Update Your App
To publish an update:
- Increment
versionCodeandversionNameinbuild.gradle.kts:
defaultConfig {
versionCode = 2 // Must be higher than previous
versionName = "1.1" // What users see
}
- Build a new AAB:
./gradlew bundleRelease - Upload to Play Console → Production → Create new release
What to Expect
| Metric | First Month (Realistic) |
|---|---|
| Installs | 10-100 (without marketing) |
| Rating | 4.0-5.0 (few ratings) |
| Crashes | Fix any within 48 hours |
| Revenue (if monetized) | $0-5 |
Don’t expect thousands of downloads on day one. Organic growth takes months. To accelerate:
- Share on social media
- Write about it on your blog
- Ask friends to install and review
- Optimize your listing (ASO — App Store Optimization)
Version Management
// build.gradle.kts
defaultConfig {
// versionCode — integer, must increase with every update
// Google Play rejects uploads with same or lower versionCode
versionCode = 1
// versionName — string, shown to users
// Follow semver: major.minor.patch
versionName = "1.0.0"
}
| versionCode | versionName | What Changed |
|---|---|---|
| 1 | 1.0.0 | Initial release |
| 2 | 1.1.0 | Added due dates |
| 3 | 1.1.1 | Fixed crash on empty list |
| 4 | 1.2.0 | Added notifications |
| 5 | 2.0.0 | Complete UI redesign |
CI/CD with GitHub Actions
Automate your release builds:
# .github/workflows/release.yml
name: Build Release
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build Release AAB
run: ./gradlew bundleRelease
env:
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
- name: Upload AAB
uses: actions/upload-artifact@v4
with:
name: release-aab
path: app/build/outputs/bundle/release/app-release.aab
Tag a release → GitHub Actions builds → download AAB → upload to Play Console.
Common Mistakes
Mistake 1: Losing the Keystore
❌ "I lost my keystore file" → You can NEVER update your app
✅ Back up keystore + passwords in a password manager
Mistake 2: Not Testing Release Build
❌ "Debug works fine, release crashes"
→ Proguard removes classes it thinks are unused
✅ Always install and test the release build before uploading
Mistake 3: Wrong Screenshot Sizes
❌ Screenshots rejected by Play Console
✅ Phone: 1080x1920 minimum. Use a Pixel emulator.
Mistake 4: Missing Privacy Policy
❌ App rejected: "Missing privacy policy"
✅ Create one, host it online, link in Play Console
Congratulations!
You did it. From “Hello World” to publishing a real app on Google Play.
In 25 tutorials, you learned:
| Part | What You Learned |
|---|---|
| Foundations | Composables, layouts, modifiers, components, state, lists, theming |
| Intermediate | Navigation, ViewModel, MVI, side effects, Retrofit, Room, Hilt |
| Advanced | Animations, Canvas, performance, testing, permissions, adaptive layouts |
| Real App | Planning, data layer, UI layer, polish, publishing |
You are now a Jetpack Compose developer. Go build something.
The Complete Series
Source Code
View the complete project on GitHub →
What’s Next?
The Jetpack Compose series is complete. But your learning continues:
- KMP Tutorial Series — share your code with iOS
- AI Coding Tools — build faster with AI
- Why Learn Rust — expand to systems programming
- Jetpack Compose Cheat Sheet — quick reference for every component and modifier.
Happy coding.