name: android-release description: App signing, bundling, and Play Store deployment automation. Use when signing APK/AAB, generating release builds, preparing Play Store upload, or configuring ProGuard. license: MIT version: 1.0.0
Android Release Skill
App signing, bundling, and Play Store deployment automation.
When to Use
- Signing APK/AAB for release
- Generating release builds
- Preparing Play Store upload
- Managing signing keys
- Configuring ProGuard/R8
Signing Configuration
keystore.properties (gitignored)
storeFile=release-key.jks
storePassword=your_store_password
keyAlias=your_key_alias
keyPassword=your_key_password
build.gradle.kts
val keystoreProperties = Properties().apply {
val file = file("keystore.properties")
if (file.exists()) file.inputStream().use { load(it) }
}
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 {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
Build Commands
# Build signed AAB (for Play Store)
./gradlew bundleRelease
# Build signed APK
./gradlew assembleRelease
# Clean and build
./gradlew clean bundleRelease
# Build with specific variant
./gradlew bundleProdRelease
ProGuard/R8 Rules
# Keep data classes for serialization
-keepclassmembers class * {
@kotlinx.serialization.Serializable *;
}
# Keep Compose
-keep class androidx.compose.** { *; }
-dontwarn androidx.compose.**
# Keep Koin
-keep class org.koin.** { *; }
# Keep Supabase/Ktor
-keep class io.github.jan.supabase.** { *; }
-keep class io.ktor.** { *; }
# Keep Retrofit models (if used)
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Remove debug logs
-assumenosideeffects class android.util.Log {
public static int d(...);
public static int v(...);
}
Play Store Deployment
Using Gradle Play Publisher Plugin
// plugins block
id("com.github.triplet.play") version "3.10.1"
play {
serviceAccountCredentials.set(file("play-service-account.json"))
track.set("internal") // internal, alpha, beta, production
defaultToAppBundles.set(true)
}
# Upload to internal testing
./gradlew publishBundle
# Upload to production
./gradlew publishReleaseBundle --track production
# Promote from internal to production
./gradlew promoteArtifact --from-track internal --to-track production
Manual Upload
- Build AAB:
./gradlew bundleRelease - Find at:
app/build/outputs/bundle/release/app-release.aab - Upload via Play Console
Version Management
android {
defaultConfig {
versionCode = 10
versionName = "1.2.0"
}
}
// Or auto-generate from git
val gitVersionCode = "git rev-list --count HEAD".execute().toInt()
val gitVersionName = "git describe --tags --always".execute()
Version Compatibility
| AGP | Gradle | JDK | Target SDK |
|---|---|---|---|
| 8.8+ | 8.10+ | 17+ | 35 |
| 8.5+ | 8.5+ | 17+ | 34 |
Error Handling
# Validate AAB before upload
bundletool validate --bundle=app-release.aab
# Check signing
jarsigner -verify -verbose -certs app-release.apk
# Test release build locally
./gradlew assembleRelease && adb install -r app/build/outputs/apk/release/app-release.apk
Troubleshooting
| Issue | Solution |
|---|---|
| Signing failed | Verify keystore path and passwords |
| ProGuard errors | Add keep rules for affected classes |
| APK too large | Enable R8 shrinking, check resources |
| Upload rejected | Check version code, target SDK |
Security Checklist
- Keystore NOT in version control
- Passwords in environment variables
- Play App Signing enabled
- ProGuard/R8 enabled for release
- Service account key secured
- Backup rules exclude sensitive data
CI/CD Integration
# GitHub Actions Release
- name: Build Release
run: ./gradlew bundleRelease
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- name: Upload to Play Store
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
packageName: com.example.app
releaseFiles: app/build/outputs/bundle/release/app-release.aab
track: internal
Release Checklist
- Version code/name incremented
- ProGuard rules updated for new libraries
- Release notes prepared
- Screenshots updated (if UI changed)
- Test on release build before upload
- Staged rollout configured
References
Use this skill for secure, automated release workflows.