fix(ci): use explicit echo blocks instead of heredocs to prevent leading whitespace in gradle.properties
Some checks failed
Frontend CI / build-and-push-web (push) Has been cancelled
Frontend CI / ota (android) (push) Has been cancelled
Frontend CI / ota (ios) (push) Has been cancelled
Frontend CI / build-android-apk (push) Successful in 45m59s

The heredoc approach (`cat >> file << EOF`) was introducing leading whitespace to each line,
causing Gradle to treat whitespace as part of property keys. This made hasProperty() return
false for signingConfig values, breaking release builds. The fix uses explicit echo blocks
that write column-0 strings without indentation artifacts.
This commit is contained in:
lafay
2026-06-18 15:37:56 +08:00
parent 1018cd7ea2
commit c1f8acd4fc

View File

@@ -133,43 +133,47 @@ jobs:
# Decode Android signing keystore # Decode Android signing keystore
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > app/withyou-release-key.keystore echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > app/withyou-release-key.keystore
# Append signing properties to gradle.properties (secrets appended after prebuild for better cache hit rate) # Append signing properties to gradle.properties (secrets appended after prebuild for better cache hit rate).
cat >> gradle.properties << 'SIGNING_PROPS' # IMPORTANT: each echo line writes a column-0 string to gradle.properties — gradle.properties keys
MYAPP_UPLOAD_STORE_FILE=withyou-release-key.keystore # cannot have leading whitespace (Gradle treats leading whitespace as part of the key name and
MYAPP_UPLOAD_STORE_PASSWORD=${{ secrets.ANDROID_KEYSTORE_PASSWORD }} # hasProperty() then returns false, breaking release signing — see app/build.gradle signingConfigs.release).
MYAPP_UPLOAD_KEY_ALIAS=withyou-key # NB: this block runs with `set -e` by default; if any echo fails the step aborts.
MYAPP_UPLOAD_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }} {
SIGNING_PROPS echo "MYAPP_UPLOAD_STORE_FILE=withyou-release-key.keystore"
echo "MYAPP_UPLOAD_STORE_PASSWORD=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}"
echo "MYAPP_UPLOAD_KEY_ALIAS=withyou-key"
echo "MYAPP_UPLOAD_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}"
} >> gradle.properties
# CI build tuning (low-memory container): force single-worker, reduce JVM heap, # CI build tuning (low-memory container): force single-worker, reduce JVM heap,
# plus restore properties that prebuild does NOT generate but the build needs. # plus restore properties that prebuild does NOT generate but the build needs.
cat >> gradle.properties << 'CI_PROPS' {
org.gradle.daemon=false echo "org.gradle.daemon=false"
org.gradle.parallel=false echo "org.gradle.parallel=false"
org.gradle.configureondemand=false echo "org.gradle.configureondemand=false"
org.gradle.workers.max=1 echo "org.gradle.workers.max=1"
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:ReservedCodeCacheSize=256m -XX:+HeapDumpOnOutOfMemoryError echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:ReservedCodeCacheSize=256m -XX:+HeapDumpOnOutOfMemoryError"
kotlin.daemon.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:ReservedCodeCacheSize=256m echo "kotlin.daemon.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:ReservedCodeCacheSize=256m"
ndkVersion=27.1.12297006 echo "ndkVersion=27.1.12297006"
systemProp.org.gradle.internal.http.connectionTimeout=30000 echo "systemProp.org.gradle.internal.http.connectionTimeout=30000"
systemProp.org.gradle.internal.http.socketTimeout=30000 echo "systemProp.org.gradle.internal.http.socketTimeout=30000"
# ExpoAutolinkingPlugin requires this; without it Gradle calls # ExpoAutolinkingPlugin requires this; without it Gradle calls
# `node ... mirror-kotlin-inline-modules --watched-directories-serialized ''` # `node ... mirror-kotlin-inline-modules --watched-directories-serialized ''`
# and node JSON.parse('') throws SyntaxError, exiting 1. # and node JSON.parse('') throws SyntaxError, exiting 1.
# See ExpoAutolinkingPlugin.kt:51 (findProperty fallback to emptyList) # See ExpoAutolinkingPlugin.kt:51 (findProperty fallback to emptyList)
# and ExpoAutolinkingPlugin.kt:67 (passes value to node as-is). # and ExpoAutolinkingPlugin.kt:67 (passes value to node as-is).
expo.inlineModules.watchedDirectories=[] echo "expo.inlineModules.watchedDirectories=[]"
CI_PROPS } >> gradle.properties
# Verify signing config in app/build.gradle # Verify signing config in app/build.gradle
echo "=== app/build.gradle signing section ===" echo "=== app/build.gradle signing section ==="
grep -A 20 'signingConfigs' app/build.gradle || echo "signingConfigs not found" grep -A 20 'signingConfigs' app/build.gradle || echo "signingConfigs not found"
# Diagnostic: dump full gradle.properties + verify expo.inlineModules property # Diagnostic: dump full gradle.properties + verify the signing property is readable
echo "=== gradle.properties (final) ===" echo "=== gradle.properties (final) ==="
cat gradle.properties cat gradle.properties
echo "=== expo.inlineModules check ===" echo "=== MYAPP_UPLOAD_STORE_FILE check ==="
grep -c '^expo\.inlineModules\.watchedDirectories=' gradle.properties || echo "MISSING expo.inlineModules.watchedDirectories" grep -c '^MYAPP_UPLOAD_STORE_FILE=' gradle.properties || echo "MISSING MYAPP_UPLOAD_STORE_FILE (column 0)"
- name: Build Android release APK (arm64 only) - name: Build Android release APK (arm64 only)
run: | run: |