From bc262274436f1624f0aabd5636f25745ddeb1024 Mon Sep 17 00:00:00 2001 From: Butterscotch! Date: Mon, 8 Dec 2025 23:24:20 -0500 Subject: [PATCH 1/4] Build and sign release with Gradle --- .github/workflows/gradle.yaml | 17 ++++++++++++++--- server/android/.gitignore | 1 + server/android/build.gradle.kts | 10 ++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gradle.yaml b/.github/workflows/gradle.yaml index 92c2c2e70..d83c9199d 100644 --- a/.github/workflows/gradle.yaml +++ b/.github/workflows/gradle.yaml @@ -113,13 +113,24 @@ jobs: - name: Install dependencies run: pnpm i - - name: Build + - name: Build GUI env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} run: cd gui && pnpm run build + - name: Decode keystore secret to file + env: + ANDROID_STORE_FILE: ${{ secrets.ANDROID_STORE_FILE }} + run: | + mkdir -p server/android/secrets/ + echo $ANDROID_STORE_FILE | base64 --decode > server/android/secrets/keystore.jks + - name: Build with Gradle - run: ./gradlew :server:android:assembleDebug + run: ./gradlew :server:android:build + env: + ANDROID_STORE_PASSWD: ${{ secrets.ANDROID_STORE_PASSWD }} + ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} + ANDROID_KEY_PASSWD: ${{ secrets.ANDROID_KEY_PASSWD }} - name: Upload the Android Build Artifact uses: actions/upload-artifact@v5 @@ -132,7 +143,7 @@ jobs: - name: Prepare for release if: startsWith(github.ref, 'refs/tags/') run: | - cp server/android/build/outputs/apk/debug/android-debug.apk ./SlimeVR-android.apk + cp server/android/build/outputs/apk/release/android-release.apk ./SlimeVR-android.apk - name: Upload to draft release uses: softprops/action-gh-release@v2 diff --git a/server/android/.gitignore b/server/android/.gitignore index 755ee59ff..c39472d4b 100644 --- a/server/android/.gitignore +++ b/server/android/.gitignore @@ -1,2 +1,3 @@ /build /src/main/resources/web-gui +/secrets diff --git a/server/android/build.gradle.kts b/server/android/build.gradle.kts index b12f28f13..c6061ec16 100644 --- a/server/android/build.gradle.kts +++ b/server/android/build.gradle.kts @@ -134,6 +134,15 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } + signingConfigs { + create("release") { + storeFile = file("./secrets/keystore.jks") + storePassword = System.getenv("ANDROID_STORE_PASSWD") + keyAlias = System.getenv("ANDROID_KEY_ALIAS") + keyPassword = System.getenv("ANDROID_KEY_PASSWD") + } + } + /* The buildTypes block is where you can configure multiple build types. By default, the build system defines two build types: debug and release. The debug build type is not explicitly shown in the default build configuration, @@ -151,6 +160,7 @@ android { getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro", ) + signingConfig = signingConfigs.getByName("release") } } From 819481adcdeac6f7e71c072aa3fe3dd2ca694467 Mon Sep 17 00:00:00 2001 From: Butterscotch! Date: Tue, 9 Dec 2025 02:30:13 -0500 Subject: [PATCH 2/4] Early fail for keystore issues --- server/android/build.gradle.kts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/android/build.gradle.kts b/server/android/build.gradle.kts index c6061ec16..b2620bb00 100644 --- a/server/android/build.gradle.kts +++ b/server/android/build.gradle.kts @@ -39,6 +39,14 @@ tasks.register("copyGuiAssets") { } tasks.preBuild { dependsOn(":server:android:copyGuiAssets") + + // Validate release keystore + val storeFile = android.buildTypes.getByName("release").signingConfig?.storeFile + if (storeFile?.isFile != true) { + throw GradleException("KeyStore file does not exist or is not a file: ${storeFile?.path}") + } else if (storeFile.length() <= 0) { + throw GradleException("KeyStore file is empty: ${storeFile.path}") + } } tasks.withType { From 712fa6a1ade57bd80d2303c366fdd4213c369898 Mon Sep 17 00:00:00 2001 From: Butterscotch! Date: Tue, 9 Dec 2025 02:55:12 -0500 Subject: [PATCH 3/4] Avoid Android Gradle project for desktop tests --- .github/workflows/gradle.yaml | 4 ++-- server/android/build.gradle.kts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/gradle.yaml b/.github/workflows/gradle.yaml index d83c9199d..926e60e30 100644 --- a/.github/workflows/gradle.yaml +++ b/.github/workflows/gradle.yaml @@ -42,7 +42,7 @@ jobs: run: ./gradlew spotlessCheck - name: Test with Gradle - run: ./gradlew test + run: ./gradlew :server:core:test :server:desktop:test build: runs-on: ubuntu-latest @@ -65,7 +65,7 @@ jobs: uses: gradle/actions/setup-gradle@v5 - name: Build with Gradle - run: ./gradlew shadowJar + run: ./gradlew :server:desktop:shadowJar - name: Upload the Server JAR as a Build Artifact uses: actions/upload-artifact@v5 diff --git a/server/android/build.gradle.kts b/server/android/build.gradle.kts index b2620bb00..e2157cd51 100644 --- a/server/android/build.gradle.kts +++ b/server/android/build.gradle.kts @@ -43,9 +43,9 @@ tasks.preBuild { // Validate release keystore val storeFile = android.buildTypes.getByName("release").signingConfig?.storeFile if (storeFile?.isFile != true) { - throw GradleException("KeyStore file does not exist or is not a file: ${storeFile?.path}") + throw GradleException("Android KeyStore file does not exist or is not a file: ${storeFile?.path}") } else if (storeFile.length() <= 0) { - throw GradleException("KeyStore file is empty: ${storeFile.path}") + throw GradleException("Android KeyStore file is empty: ${storeFile.path}") } } From 575778ab856bdc4ca8518fd46db8dca59f4e98db Mon Sep 17 00:00:00 2001 From: Butterscotch! Date: Tue, 9 Dec 2025 07:21:19 -0500 Subject: [PATCH 4/4] Don't fail for keystore --- .github/workflows/gradle.yaml | 2 +- server/android/build.gradle.kts | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/gradle.yaml b/.github/workflows/gradle.yaml index 926e60e30..96475b37e 100644 --- a/.github/workflows/gradle.yaml +++ b/.github/workflows/gradle.yaml @@ -42,7 +42,7 @@ jobs: run: ./gradlew spotlessCheck - name: Test with Gradle - run: ./gradlew :server:core:test :server:desktop:test + run: ./gradlew test build: runs-on: ubuntu-latest diff --git a/server/android/build.gradle.kts b/server/android/build.gradle.kts index e2157cd51..9e17b10d0 100644 --- a/server/android/build.gradle.kts +++ b/server/android/build.gradle.kts @@ -37,17 +37,18 @@ tasks.register("copyGuiAssets") { throw GradleException("You need to run \"pnpm run build\" on the gui folder first!") } } -tasks.preBuild { - dependsOn(":server:android:copyGuiAssets") - - // Validate release keystore +tasks.register("validateKeyStore") { val storeFile = android.buildTypes.getByName("release").signingConfig?.storeFile + // Only warn for now since this is run even when irrelevant if (storeFile?.isFile != true) { - throw GradleException("Android KeyStore file does not exist or is not a file: ${storeFile?.path}") + logger.error("Android KeyStore file does not exist or is not a file: ${storeFile?.path}") } else if (storeFile.length() <= 0) { - throw GradleException("Android KeyStore file is empty: ${storeFile.path}") + logger.error("Android KeyStore file is empty: ${storeFile.path}") } } +tasks.preBuild { + dependsOn(":server:android:copyGuiAssets", ":server:android:validateKeyStore") +} tasks.withType { compilerOptions {