feat: implement production release configuration and signing for Play Store
This commit is contained in:
@@ -141,6 +141,11 @@ Kurz: Ziel ist eine native Android-App mit Kotlin + Jetpack Compose, die die Web
|
|||||||
[ ] 22. Analytics: Firebase / Matomo Integration (je nach Datenschutz)
|
[ ] 22. Analytics: Firebase / Matomo Integration (je nach Datenschutz)
|
||||||
[x] 23. Crash-Reporting: Sentry / Crashlytics integrieren
|
[x] 23. Crash-Reporting: Sentry / Crashlytics integrieren
|
||||||
[ ] 24. Build/Release: App signing, Release-Notes, Play-Store-Metadaten vorbereiten
|
[ ] 24. Build/Release: App signing, Release-Notes, Play-Store-Metadaten vorbereiten
|
||||||
|
- [x] Technische Release-Basis vorbereitet: `ANDROID_VERSION_CODE` und `ANDROID_VERSION_NAME` als Gradle-Properties eingeführt (`android-app/gradle.properties`) und im App-Gradle verdrahtet.
|
||||||
|
- [x] Production-Release-Flavor auf Produktiv-Backend parametrisierbar gemacht (`PRODUCTION_API_BASE_URL`, Default `https://harheimertc.de/`).
|
||||||
|
- [x] Release-Signing per sicheren Gradle-Properties vorbereitet (`RELEASE_STORE_FILE`, `RELEASE_STORE_PASSWORD`, `RELEASE_KEY_ALIAS`, `RELEASE_KEY_PASSWORD`) statt Hardcoding.
|
||||||
|
- [x] `:app:assembleProductionRelease` erfolgreich gebaut (Stand 2026-05-29).
|
||||||
|
- [ ] Offen: Finales Upload-Keystore + Credentials in CI/Build-Host hinterlegen, Play-Store-Release-Notes und Store-Metadaten pflegen.
|
||||||
[ ] 25. Dokumentation: `README-android.md` mit Setup, Architektur und Release-Anleitung
|
[ ] 25. Dokumentation: `README-android.md` mit Setup, Architektur und Release-Anleitung
|
||||||
|
|
||||||
5) Kurzzeit-MVP (Priorität für erste Version)
|
5) Kurzzeit-MVP (Priorität für erste Version)
|
||||||
|
|||||||
@@ -8,9 +8,31 @@ plugins {
|
|||||||
val localApiBaseUrl = providers.gradleProperty("LOCAL_API_BASE_URL")
|
val localApiBaseUrl = providers.gradleProperty("LOCAL_API_BASE_URL")
|
||||||
.orElse("https://harheimertc.tsschulz.de/")
|
.orElse("https://harheimertc.tsschulz.de/")
|
||||||
.get()
|
.get()
|
||||||
|
val productionApiBaseUrl = providers.gradleProperty("PRODUCTION_API_BASE_URL")
|
||||||
|
.orElse("https://harheimertc.de/")
|
||||||
|
.get()
|
||||||
val sentryDsn = providers.gradleProperty("SENTRY_DSN")
|
val sentryDsn = providers.gradleProperty("SENTRY_DSN")
|
||||||
.orElse("")
|
.orElse("")
|
||||||
.get()
|
.get()
|
||||||
|
val androidVersionCode = providers.gradleProperty("ANDROID_VERSION_CODE")
|
||||||
|
.orElse("2")
|
||||||
|
.get()
|
||||||
|
.toInt()
|
||||||
|
val androidVersionName = providers.gradleProperty("ANDROID_VERSION_NAME")
|
||||||
|
.orElse("1.0.0")
|
||||||
|
.get()
|
||||||
|
val releaseMinifyEnabled = providers.gradleProperty("RELEASE_MINIFY_ENABLED")
|
||||||
|
.orElse("true")
|
||||||
|
.get()
|
||||||
|
.toBoolean()
|
||||||
|
val releaseStoreFile = providers.gradleProperty("RELEASE_STORE_FILE").orNull
|
||||||
|
val releaseStorePassword = providers.gradleProperty("RELEASE_STORE_PASSWORD").orNull
|
||||||
|
val releaseKeyAlias = providers.gradleProperty("RELEASE_KEY_ALIAS").orNull
|
||||||
|
val releaseKeyPassword = providers.gradleProperty("RELEASE_KEY_PASSWORD").orNull
|
||||||
|
val hasReleaseSigning = !releaseStoreFile.isNullOrBlank() &&
|
||||||
|
!releaseStorePassword.isNullOrBlank() &&
|
||||||
|
!releaseKeyAlias.isNullOrBlank() &&
|
||||||
|
!releaseKeyPassword.isNullOrBlank()
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "de.harheimertc"
|
namespace = "de.harheimertc"
|
||||||
@@ -19,9 +41,38 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "de.harheimertc"
|
applicationId = "de.harheimertc"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 34
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = androidVersionCode
|
||||||
versionName = "0.1.0"
|
versionName = androidVersionName
|
||||||
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
create("release") {
|
||||||
|
if (hasReleaseSigning) {
|
||||||
|
storeFile = file(releaseStoreFile!!)
|
||||||
|
storePassword = releaseStorePassword
|
||||||
|
keyAlias = releaseKeyAlias
|
||||||
|
keyPassword = releaseKeyPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
getByName("release") {
|
||||||
|
isMinifyEnabled = releaseMinifyEnabled
|
||||||
|
isShrinkResources = false
|
||||||
|
ndk {
|
||||||
|
// Generate a native debug symbols archive for Play Console uploads.
|
||||||
|
debugSymbolLevel = "SYMBOL_TABLE"
|
||||||
|
}
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro",
|
||||||
|
)
|
||||||
|
if (hasReleaseSigning) {
|
||||||
|
signingConfig = signingConfigs.getByName("release")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions += "environment"
|
flavorDimensions += "environment"
|
||||||
@@ -46,7 +97,7 @@ android {
|
|||||||
}
|
}
|
||||||
create("production") {
|
create("production") {
|
||||||
dimension = "environment"
|
dimension = "environment"
|
||||||
buildConfigField("String", "API_BASE_URL", "\"https://harheimertc.tsschulz.de/\"")
|
buildConfigField("String", "API_BASE_URL", "\"$productionApiBaseUrl\"")
|
||||||
buildConfigField("String", "SENTRY_DSN", "\"$sentryDsn\"")
|
buildConfigField("String", "SENTRY_DSN", "\"$sentryDsn\"")
|
||||||
buildConfigField("String", "ENVIRONMENT_NAME", "\"\"")
|
buildConfigField("String", "ENVIRONMENT_NAME", "\"\"")
|
||||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||||
@@ -72,6 +123,44 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val packageNativeDebugSymbolsForProductionRelease = tasks.register<Zip>("packageNativeDebugSymbolsForProductionRelease") {
|
||||||
|
group = "distribution"
|
||||||
|
description = "Packages production release native libraries into a Play Console debug symbols zip."
|
||||||
|
dependsOn(":app:mergeProductionReleaseNativeLibs")
|
||||||
|
from(layout.buildDirectory.dir("intermediates/merged_native_libs/productionRelease/mergeProductionReleaseNativeLibs/out/lib"))
|
||||||
|
destinationDirectory.set(layout.buildDirectory.dir("outputs/native-debug-symbols/productionRelease"))
|
||||||
|
archiveFileName.set("native-debug-symbols.zip")
|
||||||
|
}
|
||||||
|
|
||||||
|
val collectPlayStoreArtifacts = tasks.register("collectPlayStoreArtifacts") {
|
||||||
|
group = "distribution"
|
||||||
|
description = "Builds production release artifacts and collects AAB, mapping, and native symbols for Play Console upload."
|
||||||
|
dependsOn(":app:bundleProductionRelease")
|
||||||
|
dependsOn(packageNativeDebugSymbolsForProductionRelease)
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
val outputDir = layout.buildDirectory.dir("outputs/playstore/productionRelease").get().asFile
|
||||||
|
outputDir.mkdirs()
|
||||||
|
|
||||||
|
val bundleFile = layout.buildDirectory.file("outputs/bundle/productionRelease/app-production-release.aab").get().asFile
|
||||||
|
if (bundleFile.exists()) {
|
||||||
|
bundleFile.copyTo(outputDir.resolve(bundleFile.name), overwrite = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mappingFile = layout.buildDirectory.file("outputs/mapping/productionRelease/mapping.txt").get().asFile
|
||||||
|
if (mappingFile.exists()) {
|
||||||
|
mappingFile.copyTo(outputDir.resolve("mapping.txt"), overwrite = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val nativeSymbolsZip = layout.buildDirectory.file("outputs/native-debug-symbols/productionRelease/native-debug-symbols.zip").get().asFile
|
||||||
|
if (nativeSymbolsZip.exists()) {
|
||||||
|
nativeSymbolsZip.copyTo(outputDir.resolve("native-debug-symbols.zip"), overwrite = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Play Store artifacts prepared in: ${outputDir.absolutePath}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
||||||
|
|||||||
BIN
android-app/app/instantTest/release/app-instantTest-release.aab
Normal file
BIN
android-app/app/instantTest/release/app-instantTest-release.aab
Normal file
Binary file not shown.
BIN
android-app/app/local/release/app-local-release.aab
Normal file
BIN
android-app/app/local/release/app-local-release.aab
Normal file
Binary file not shown.
BIN
android-app/app/production/release/app-production-release.aab
Normal file
BIN
android-app/app/production/release/app-production-release.aab
Normal file
Binary file not shown.
2
android-app/app/proguard-rules.pro
vendored
Normal file
2
android-app/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Project-specific R8/ProGuard rules for release builds.
|
||||||
|
# Keep this file intentionally minimal and add rules only when needed.
|
||||||
@@ -3,3 +3,22 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
|
|||||||
org.gradle.workers.max=2
|
org.gradle.workers.max=2
|
||||||
# Local API base URL for running the app from Android Studio / Gradle
|
# Local API base URL for running the app from Android Studio / Gradle
|
||||||
LOCAL_API_BASE_URL=https://harheimertc.tsschulz.de/
|
LOCAL_API_BASE_URL=https://harheimertc.tsschulz.de/
|
||||||
|
|
||||||
|
# Production backend for Play Store build variant
|
||||||
|
PRODUCTION_API_BASE_URL=https://harheimertc.de/
|
||||||
|
|
||||||
|
# Android app versioning for Play Store uploads
|
||||||
|
ANDROID_VERSION_CODE=3
|
||||||
|
ANDROID_VERSION_NAME=1.0.0
|
||||||
|
|
||||||
|
# Enable R8 for release by default so mapping.txt is generated for Play Console.
|
||||||
|
RELEASE_MINIFY_ENABLED=true
|
||||||
|
|
||||||
|
# Release signing (set in local, untracked gradle.properties or via CI secrets)
|
||||||
|
# RELEASE_STORE_FILE=/absolute/path/to/keystore.jks
|
||||||
|
# RELEASE_STORE_PASSWORD=***
|
||||||
|
# RELEASE_KEY_ALIAS=***
|
||||||
|
# RELEASE_KEY_PASSWORD=***
|
||||||
|
|
||||||
|
# Build and collect Play Store upload artifacts:
|
||||||
|
# ./gradlew :app:collectPlayStoreArtifacts
|
||||||
|
|||||||
Reference in New Issue
Block a user