From 7bdc5283bafe60f6bb0cb150b9e6528ce7629709 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 14:17:33 +0000 Subject: [PATCH 1/2] Add tagged release workflow with installable signed APKs Pushing a vX.Y.Z tag now builds app:assembleRelease and publishes a GitHub Release with the minified APK attached and auto-generated notes, separate from the existing rolling debug-latest build. Since there's no managed release keystore yet, the release build type signs with the debug key so the APK stays installable. https://claude.ai/code/session_01J194Wop2SixMd1HPS5PbcS --- .github/workflows/android-release.yml | 59 +++++++++++++++++++++++++++ app/build.gradle.kts | 3 ++ 2 files changed, 62 insertions(+) create mode 100644 .github/workflows/android-release.yml diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml new file mode 100644 index 0000000..a802af9 --- /dev/null +++ b/.github/workflows/android-release.yml @@ -0,0 +1,59 @@ +name: Release + +on: + push: + tags: + - 'v*.*.*' + +permissions: + contents: write + +jobs: + build: + name: Build and publish release APK + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + cache: gradle + + - name: Set up Android SDK + uses: android-actions/setup-android@v3 + + - name: Make Gradle wrapper executable + run: chmod +x ./gradlew + + - name: Build release APK + run: ./gradlew :app:assembleRelease --stacktrace + + - name: Prepare release APK + run: | + set -euo pipefail + mkdir -p dist + APK_PATH="$(find app/build/outputs/apk/release -name '*.apk' | head -n 1)" + cp "$APK_PATH" "dist/Sploot-${GITHUB_REF_NAME}.apk" + + - name: Upload release APK artifact + uses: actions/upload-artifact@v4 + with: + name: Sploot-release-apk + path: dist/Sploot-${{ github.ref_name }}.apk + if-no-files-found: error + + - name: Create GitHub release + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + gh release create "${GITHUB_REF_NAME}" "dist/Sploot-${GITHUB_REF_NAME}.apk" \ + --title "Sploot ${GITHUB_REF_NAME}" \ + --generate-notes diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f04e639..73fb5bb 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -26,6 +26,9 @@ android { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) + // No managed release keystore yet; sign with the debug key so + // release builds stay installable until a real signing config exists. + signingConfig = signingConfigs.getByName("debug") } } From 5cb1799b012c27b4aeb73c7d41e31b6c4afdd7ab Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 14:20:05 +0000 Subject: [PATCH 2/2] Wire real release signing into the release workflow Adds a release signingConfig that reads the keystore path and credentials from environment variables, falling back to debug signing when they're unset (e.g. local builds). The release workflow decodes a base64-encoded keystore secret and passes the credentials through so tagged releases are signed with a real release key instead of the debug key. https://claude.ai/code/session_01J194Wop2SixMd1HPS5PbcS --- .github/workflows/android-release.yml | 16 ++++++++++++++++ app/build.gradle.kts | 19 ++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml index a802af9..e7dc7d0 100644 --- a/.github/workflows/android-release.yml +++ b/.github/workflows/android-release.yml @@ -32,7 +32,23 @@ jobs: - name: Make Gradle wrapper executable run: chmod +x ./gradlew + - name: Decode release keystore + env: + RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }} + run: | + set -euo pipefail + if [ -n "${RELEASE_KEYSTORE_BASE64:-}" ]; then + echo "$RELEASE_KEYSTORE_BASE64" | base64 -d > "$RUNNER_TEMP/release.keystore" + echo "RELEASE_KEYSTORE_PATH=$RUNNER_TEMP/release.keystore" >> "$GITHUB_ENV" + else + echo "::warning::RELEASE_KEYSTORE_BASE64 secret not set; release APK will be debug-signed." + fi + - name: Build release APK + env: + RELEASE_KEYSTORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_PASSWORD }} + RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }} + RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }} run: ./gradlew :app:assembleRelease --stacktrace - name: Prepare release APK diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 73fb5bb..7f834b6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,6 +19,18 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } + val releaseKeystorePath = System.getenv("RELEASE_KEYSTORE_PATH") + signingConfigs { + if (releaseKeystorePath != null) { + create("release") { + storeFile = file(releaseKeystorePath) + storePassword = System.getenv("RELEASE_KEYSTORE_PASSWORD") + keyAlias = System.getenv("RELEASE_KEY_ALIAS") + keyPassword = System.getenv("RELEASE_KEY_PASSWORD") + } + } + } + buildTypes { release { isMinifyEnabled = true @@ -26,9 +38,10 @@ android { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) - // No managed release keystore yet; sign with the debug key so - // release builds stay installable until a real signing config exists. - signingConfig = signingConfigs.getByName("debug") + // Falls back to debug signing for local builds where the release + // keystore env vars aren't set, e.g. outside of the release CI job. + signingConfig = signingConfigs.findByName("release") + ?: signingConfigs.getByName("debug") } }