diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a3e3a28b..e9629caa3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,11 @@ jobs: echo "ndk.dir=${ANDROID_HOME}/ndk/25.0.8775105" >> local.properties export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}" ./run init action gradle - KEYSTORE_PASS="${{ secrets.KEYSTORE_PASS }}" ALIAS_NAME="${{ secrets.ALIAS_NAME }}" ALIAS_PASS="${{ secrets.ALIAS_PASS}}" ./gradlew app:assembleOssRelease + # release.keystore is not committed; decode it from the KEYSTORE_B64 secret. + if [ -n "${{ secrets.KEYSTORE_B64 }}" ]; then + echo "${{ secrets.KEYSTORE_B64 }}" | base64 -d > release.keystore + fi + KEYSTORE_PASS="${{ secrets.KEYSTORE_PASS }}" ALIAS_NAME="${{ secrets.ALIAS_NAME }}" ALIAS_PASS="${{ secrets.ALIAS_PASS }}" ./gradlew app:assembleOssRelease APK=$(find app/build/outputs/apk -name '*arm64-v8a*.apk') APK=$(dirname $APK) echo "APK=$APK" >> $GITHUB_ENV diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db3a97b57..4b4c344a4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,7 +130,11 @@ jobs: echo "ndk.dir=${ANDROID_HOME}/ndk/25.0.8775105" >> local.properties export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}" ./run init action gradle - KEYSTORE_PASS="${{ secrets.KEYSTORE_PASS }}" ALIAS_NAME="${{ secrets.ALIAS_NAME }}" ALIAS_PASS="${{ secrets.ALIAS_PASS}}" ./gradlew app:assembleOssRelease + # release.keystore is not committed; decode it from the KEYSTORE_B64 secret. + if [ -n "${{ secrets.KEYSTORE_B64 }}" ]; then + echo "${{ secrets.KEYSTORE_B64 }}" | base64 -d > release.keystore + fi + KEYSTORE_PASS="${{ secrets.KEYSTORE_PASS }}" ALIAS_NAME="${{ secrets.ALIAS_NAME }}" ALIAS_PASS="${{ secrets.ALIAS_PASS }}" ./gradlew app:assembleOssRelease APK=$(find app/build/outputs/apk -name '*arm64-v8a*.apk') APK=$(dirname $APK) echo "APK=$APK" >> $GITHUB_ENV diff --git a/.gitignore b/.gitignore index 3debf396c..44eaae38a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,9 @@ __MACOSX/ .gradle/ .kotlin/ build/ +# buildSrc/build is sometimes a symlink to APFS /tmp (exFAT AppleDouble workaround); +# the trailing-slash 'build/' rule above doesn't match a symlink, so ignore it explicitly. +buildSrc/build # Android / native build outputs /captures/ diff --git a/buildSrc/src/main/kotlin/Helpers.kt b/buildSrc/src/main/kotlin/Helpers.kt index 3561cdd1e..0a758e6a8 100644 --- a/buildSrc/src/main/kotlin/Helpers.kt +++ b/buildSrc/src/main/kotlin/Helpers.kt @@ -118,12 +118,22 @@ fun Project.setupAppCommon() { val keystorePwd = lp.getProperty("KEYSTORE_PASS") ?: System.getenv("KEYSTORE_PASS") val alias = lp.getProperty("ALIAS_NAME") ?: System.getenv("ALIAS_NAME") val pwd = lp.getProperty("ALIAS_PASS") ?: System.getenv("ALIAS_PASS") + // release.keystore is intentionally NOT committed (gitignored). CI decodes it from + // the KEYSTORE_B64 secret before the release build. Only wire up release signing when + // the keystore file is actually present and a (non-blank) password is provided; + // otherwise skip it so debug / PR / keyless builds don't fail. Empty-string env vars + // (unset GitHub secrets expand to "") count as absent. + val releaseKeystore = rootProject.file("release.keystore") + val canSign = releaseKeystore.exists() && + !keystorePwd.isNullOrBlank() && + !alias.isNullOrBlank() && + !pwd.isNullOrBlank() android.apply { - if (keystorePwd != null) { + if (canSign) { signingConfigs { create("release") { - storeFile = rootProject.file("release.keystore") + storeFile = releaseKeystore storePassword = keystorePwd keyAlias = alias keyPassword = pwd