GCP Cloud Build构建签名APK时密钥库文件找不到的问题
错误信息
Step #2: - In plugin 'com.android.internal.version-check' type 'com.android.build.gradle.tasks.PackageApplication' property 'signingConfigData.signingConfigData.storeFile' specifies file '/root/.gradle/daemon/7.5/keystore.jks' which doesn't exist.
App级build.gradle的release签名配置
signingConfigs { debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } release { storeFile file(System.getProperty("user.home") + "/.gradle/daemon/7.5/keystore.jks") storePassword System.getenv("GCLOUD_KEYSTORE_PASSWORD") keyAlias System.getenv("GCLOUD_KEY_ALIAS") keyPassword System.getenv("GCLOUD_KEY_PASSWORD") } } buildTypes { debug { signingConfig signingConfigs.debug buildConfigField("String", "BUGSNAG_KEY", "\"${System.env.BUGSNAG_KEY}\"") } release { // Caution! In production, you need to generate your own keystore file. minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" buildConfigField("String", "BUGSNAG_KEY", "\"${System.env.BUGSNAG_KEY}\"") signingConfig signingConfigs.release } }
cloudbuild.yaml配置
steps: - name: 'gcr.io/ronin-pos/gradle-node-android:latest' entrypoint: 'bash' args: - '-c' - | export ANDROID_SDK_ROOT=/opt/android-sdk export NODE_OPTIONS=--openssl-legacy-provider apt-get update apt-get install -y unzip curl openjdk-11-jdk # Install unzip, curl, and JDK export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 # Set JAVA_HOME export PATH=$$JAVA_HOME/bin:$$PATH:/usr/bin:/usr/local/bin:/usr/sbin:/usr/local/sbin:/opt/android-sdk/platform-tools:/opt/android-sdk/cmdline-tools/latest/bin export REACT_APP_HASURA_GRAPHQL_SECRET=$(gcloud secrets versions access latest --secret="_REACT_APP_HASURA_GRAPHQL_SECRET") export BUGSNAG_KEY=$(gcloud secrets versions access latest --secret="_BUGSNAG_KEY") export DD_CLIENT_TOKEN=$(gcloud secrets versions access latest --secret="_DD_CLIENT_TOKEN") export DD_APPLICATION_ID=$(gcloud secrets versions access latest --secret="_DD_APPLICATION_ID") export HASURA_ADMIN_SECRET=$(gcloud secrets versions access latest --secret="_HASURA_ADMIN_SECRET") export PRODUCTION_REACT_APP_HASURA_GRAPHQL_SECRET=$(gcloud secrets versions access latest --secret="_PRODUCTION_REACT_APP_HASURA_GRAPHQL_SECRET") export PRODUCTION_BUGSNAG_KEY=$(gcloud secrets versions access latest --secret="_PRODUCTION_BUGSNAG_KEY") # Ensure the .gradle/daemon/7.5 directory exists mkdir -p $$HOME/.gradle/daemon/7.5 # Access secrets directly without substitutions export GCLOUD_KEYSTORE_CONTENT=$(gcloud secrets versions access latest --secret="GCLOUD_KEYSTORE_CONTENT") export GCLOUD_KEYSTORE_PASSWORD=$(gcloud secrets versions access latest --secret="GCLOUD_KEYSTORE_PASSWORD") export GCLOUD_KEY_ALIAS=$(gcloud secrets versions access latest --secret="GCLOUD_KEY_ALIAS") export GCLOUD_KEY_PASSWORD=$(gcloud secrets versions access latest --secret="GCLOUD_KEY_PASSWORD") # Validate that the keystore file was created successfully if [ ! -f $$HOME/.gradle/daemon/7.5/keystore.jks ]; then echo "Error: Keystore file could not be created." ls -l $$HOME/.gradle/daemon/7.5 exit 1 fi echo $$GCLOUD_KEYSTORE_CONTENT | base64 --decode > $$HOME/.gradle/daemon/7.5/keystore.jks cd android chmod +x ./gradlew ./gradlew clean assembleRelease -Pandroid.injected.signing.store.file=$$HOME/.gradle/daemon/7.5/keystore.jks \ -Pandroid.injected.signing.store.password=$$GCLOUD_KEYSTORE_PASSWORD \ -Pandroid.injected.signing.key.alias=$$GCLOUD_KEY_ALIAS \ -Pandroid.injected.signing.key.password=$$GCLOUD_KEY_PASSWORD
环境信息
- Node.js 18.0.0
- Gradle 7.5
- React Native 0.67.4
- 项目正从AppCenter迁移至GCP,密钥存储在Google Secrets Manager中
1. 调整密钥库文件生成与校验顺序
当前cloudbuild.yaml中先校验文件是否存在,再生成文件,会直接触发错误退出。将校验逻辑移到文件生成之后:
# 先生成密钥库文件 echo $$GCLOUD_KEYSTORE_CONTENT | base64 --decode > $$HOME/.gradle/daemon/7.5/keystore.jks # 再校验文件是否存在 if [ ! -f $$HOME/.gradle/daemon/7.5/keystore.jks ]; then echo "Error: Keystore file could not be created." ls -l $$HOME/.gradle/daemon/7.5 exit 1 fi
2. 更换稳定的密钥库存储路径
.gradle/daemon/7.5是Gradle守护进程的临时目录,可能存在权限或自动清理问题,建议更换路径:
- 修改build.gradle中的路径:
release { storeFile file(System.getProperty("user.home") + "/keystore/keystore.jks") // 其他配置不变 }
- 同步修改cloudbuild.yaml:
# 创建目标目录 mkdir -p $$HOME/keystore # 生成密钥库文件 echo $$GCLOUD_KEYSTORE_CONTENT | base64 --decode > $$HOME/keystore/keystore.jks # 更新gradle命令参数 ./gradlew clean assembleRelease -Pandroid.injected.signing.store.file=$$HOME/keystore/keystore.jks \ -Pandroid.injected.signing.store.password=$$GCLOUD_KEYSTORE_PASSWORD \ -Pandroid.injected.signing.key.alias=$$GCLOUD_KEY_ALIAS \ -Pandroid.injected.signing.key.password=$$GCLOUD_KEY_PASSWORD
3. 统一签名配置来源,避免冲突
当前build.gradle的签名配置与gradle命令行注入的参数存在冲突,建议二选一:
选项A:保留build.gradle配置,移除命令行参数
删除gradle命令中所有-Pandroid.injected.signing.*相关参数,让build.gradle直接读取环境变量。
选项B:用命令行参数覆盖,简化build.gradle
修改build.gradle的release配置,放弃硬编码签名信息,完全依赖命令行注入:
release { minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" buildConfigField("String", "BUGSNAG_KEY", "\"${System.env.BUGSNAG_KEY}\"") // 不指定signingConfig,Gradle会自动使用命令行注入的签名信息 }
4. 验证密钥库Base64编码正确性
确保Google Secrets Manager中存储的GCLOUD_KEYSTORE_CONTENT是密钥库文件的原始Base64编码,无多余换行或空格。本地验证方法:
echo "你的Base64内容" | base64 --decode > test.jks keytool -list -v -keystore test.jks
若能正常读取密钥库信息,说明编码正确;否则需重新上传正确的Base64内容到Secrets Manager。
内容的提问来源于stack exchange,提问作者Connor Clark

