diff --git a/README.md b/README.md index 426e7c6d..1c95dbf1 100644 --- a/README.md +++ b/README.md @@ -66,3 +66,7 @@ Free models accessible via an API can be found [here](https://github.com/cheahjs If you in your Google account identified as under 18, you need an adult account because Google is (unreasonably) denying you the API key. Preview models will eventually be removed by Google and unfortunately won't be redirected to finished equivalents. If this happens, please change the API in the code. + +## CI Release Signing + +Dokumentation für CI-Secrets und Verhalten bei fehlender Signing-Konfiguration: [docs/ci-signing.md](docs/ci-signing.md) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8e1528cb..c82c475a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,4 +1,3 @@ - plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -14,6 +13,21 @@ System.getenv("SCREENOPERATOR_BUILD_DIR")?.takeIf { it.isNotBlank() }?.let { cus layout.buildDirectory = file(customBuildDir) } +val releaseSigningEnv = mapOf( + "ANDROID_KEYSTORE_PATH" to System.getenv("ANDROID_KEYSTORE_PATH"), + "ANDROID_KEY_ALIAS" to System.getenv("ANDROID_KEY_ALIAS"), + "ANDROID_KEYSTORE_PASSWORD" to System.getenv("ANDROID_KEYSTORE_PASSWORD"), + "ANDROID_KEY_PASSWORD" to System.getenv("ANDROID_KEY_PASSWORD"), +) + +val missingReleaseSigningEnv = releaseSigningEnv + .filterValues { it.isNullOrBlank() } + .keys + +val isReleaseTaskRequested = gradle.startParameter.taskNames.any { task -> + task.contains("release", ignoreCase = true) +} + android { namespace = "com.google.ai.sample" compileSdk = 35 @@ -34,12 +48,27 @@ android { } } + signingConfigs { + create("release") { + if (missingReleaseSigningEnv.isEmpty()) { + storeFile = file(releaseSigningEnv.getValue("ANDROID_KEYSTORE_PATH")!!) + storePassword = releaseSigningEnv.getValue("ANDROID_KEYSTORE_PASSWORD") + keyAlias = releaseSigningEnv.getValue("ANDROID_KEY_ALIAS") + keyPassword = releaseSigningEnv.getValue("ANDROID_KEY_PASSWORD") + } + } + } + buildTypes { getByName("debug") { isDebuggable = true } getByName("release") { isDebuggable = false + if (missingReleaseSigningEnv.isEmpty()) { + signingConfig = signingConfigs.getByName("release") + } + } } create("samples") { initWith(getByName("debug")) @@ -67,6 +96,13 @@ android { } } +if (isReleaseTaskRequested && missingReleaseSigningEnv.isNotEmpty()) { + error( + "Release signing env vars missing for module :app: ${missingReleaseSigningEnv.joinToString(", ")}. " + + "Set ANDROID_KEYSTORE_PATH, ANDROID_KEY_ALIAS, ANDROID_KEYSTORE_PASSWORD and ANDROID_KEY_PASSWORD." + ) +} + dependencies { constraints { implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.20") diff --git a/docs/ci-signing.md b/docs/ci-signing.md new file mode 100644 index 00000000..1758ae5c --- /dev/null +++ b/docs/ci-signing.md @@ -0,0 +1,19 @@ +# CI Signing für Release-Builds + +Die Module `app` und `humanoperator` erwarten für Release-Tasks eine Signing-Konfiguration über Umgebungsvariablen. + +## Benötigte CI-Secrets + +- `ANDROID_KEYSTORE_PATH`: Absoluter oder relativ zum Projekt auflösbarer Pfad zur Keystore-Datei. +- `ANDROID_KEY_ALIAS`: Alias des Release-Keys. +- `ANDROID_KEYSTORE_PASSWORD`: Passwort der Keystore-Datei. +- `ANDROID_KEY_PASSWORD`: Passwort des Keys. + +## Verhalten bei fehlenden Variablen + +- Für **Release-Tasks** (Taskname enthält `release`) wird der Build mit einer klaren Fehlermeldung abgebrochen, wenn eine der Variablen fehlt. +- Für Nicht-Release-Tasks bleibt die Signing-Config ungesetzt, damit lokale Debug-Builds weiter funktionieren. + +## Wichtiger Hinweis zu Firebase + +`google-services.json` bleibt unverändert versioniert und ist **nicht** Teil der Signing-Logik. diff --git a/humanoperator/build.gradle.kts b/humanoperator/build.gradle.kts index 9091bc13..180f1241 100644 --- a/humanoperator/build.gradle.kts +++ b/humanoperator/build.gradle.kts @@ -4,6 +4,21 @@ plugins { id("com.google.gms.google-services") } +val releaseSigningEnv = mapOf( + "ANDROID_KEYSTORE_PATH" to System.getenv("ANDROID_KEYSTORE_PATH"), + "ANDROID_KEY_ALIAS" to System.getenv("ANDROID_KEY_ALIAS"), + "ANDROID_KEYSTORE_PASSWORD" to System.getenv("ANDROID_KEYSTORE_PASSWORD"), + "ANDROID_KEY_PASSWORD" to System.getenv("ANDROID_KEY_PASSWORD"), +) + +val missingReleaseSigningEnv = releaseSigningEnv + .filterValues { it.isNullOrBlank() } + .keys + +val isReleaseTaskRequested = gradle.startParameter.taskNames.any { task -> + task.contains("release", ignoreCase = true) +} + android { namespace = "com.screenoperator.humanoperator" compileSdk = 35 @@ -21,10 +36,25 @@ android { } } + signingConfigs { + create("release") { + if (missingReleaseSigningEnv.isEmpty()) { + storeFile = file(releaseSigningEnv.getValue("ANDROID_KEYSTORE_PATH")!!) + storePassword = releaseSigningEnv.getValue("ANDROID_KEYSTORE_PASSWORD") + keyAlias = releaseSigningEnv.getValue("ANDROID_KEY_ALIAS") + keyPassword = releaseSigningEnv.getValue("ANDROID_KEY_PASSWORD") + } + } + } + buildTypes { release { isMinifyEnabled = false proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + if (missingReleaseSigningEnv.isEmpty()) { + signingConfig = signingConfigs.getByName("release") + } + } } } @@ -43,6 +73,13 @@ android { } } +if (isReleaseTaskRequested && missingReleaseSigningEnv.isNotEmpty()) { + error( + "Release signing env vars missing for module :humanoperator: ${missingReleaseSigningEnv.joinToString(", ")}. " + + "Set ANDROID_KEYSTORE_PATH, ANDROID_KEY_ALIAS, ANDROID_KEYSTORE_PASSWORD and ANDROID_KEY_PASSWORD." + ) +} + dependencies { implementation("androidx.core:core-ktx:1.9.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")