From 4fadb113aac21f6eb0e82b824636cbcdf24ec18e Mon Sep 17 00:00:00 2001 From: Android PowerUser <88908510+Android-PowerUser@users.noreply.github.com> Date: Sun, 26 Apr 2026 22:32:55 +0200 Subject: [PATCH 1/3] Add CI-safe release signing config for app modules --- README.md | 4 ++++ app/build.gradle.kts | 35 +++++++++++++++++++++++++++++++++- docs/ci-signing.md | 19 ++++++++++++++++++ humanoperator/build.gradle.kts | 34 +++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 docs/ci-signing.md 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..13fcc366 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,24 @@ 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 + signingConfig = signingConfigs.getByName("release") } create("samples") { initWith(getByName("debug")) @@ -67,6 +93,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..35cf98ce 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,22 @@ 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") + signingConfig = signingConfigs.getByName("release") } } @@ -43,6 +70,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") From 15dabfb26f689c640b83fba6f14f37428d6ad05c Mon Sep 17 00:00:00 2001 From: Android PowerUser <88908510+Android-PowerUser@users.noreply.github.com> Date: Sun, 26 Apr 2026 22:36:37 +0200 Subject: [PATCH 2/3] Update app/build.gradle.kts Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com> --- app/build.gradle.kts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 13fcc366..c82c475a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,10 @@ android { } getByName("release") { isDebuggable = false - signingConfig = signingConfigs.getByName("release") + if (missingReleaseSigningEnv.isEmpty()) { + signingConfig = signingConfigs.getByName("release") + } + } } create("samples") { initWith(getByName("debug")) From d243655206953f119cd6c68e879bce3de8fe5b57 Mon Sep 17 00:00:00 2001 From: Android PowerUser <88908510+Android-PowerUser@users.noreply.github.com> Date: Sun, 26 Apr 2026 22:37:11 +0200 Subject: [PATCH 3/3] Update humanoperator/build.gradle.kts Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com> --- humanoperator/build.gradle.kts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/humanoperator/build.gradle.kts b/humanoperator/build.gradle.kts index 35cf98ce..180f1241 100644 --- a/humanoperator/build.gradle.kts +++ b/humanoperator/build.gradle.kts @@ -51,7 +51,10 @@ android { release { isMinifyEnabled = false proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") - signingConfig = signingConfigs.getByName("release") + if (missingReleaseSigningEnv.isEmpty()) { + signingConfig = signingConfigs.getByName("release") + } + } } }