读取 Android 项目中的 Jenkins 环境变量?为自动构建签署 APK

Read Jenkins environment variables in Android project? Sign APK for automated builds

以为我会通过搜索找到答案,但没有运气。我计划自动化我的构建过程并通过我的 Jenkins 服务器上的 fastlane 将构建上传到 Crashlytics BetaCrashlytics beta 需要签名的 APKS,但我当然不想将我的 keystore 和密码直接添加到我的 build.gradle 文件中,然后再进入版本控制。

我被指向了 Jenkins 环境变量的方向。这是我在 Android 项目中的内容:

signingConfigs {
   release {
        storeFile file(ANDROID_KEYSTORE)
        storePassword ANDROID_STORE_PASSWORD
        keyAlias ANDROID_KEY_ALIAS
        keyPassword ANDROID_STORE_PASSWORD
   }
}

然后在我的 gradle.properties 文件中有以下内容:

ANDROID_KEYSTORE=$ANDROID_KEYSTORE
ANDROID_STORE_PASSWORD=$ANDROID_STORE_PASSWORD
ANDROID_KEY_ALIAS=$ANDROID_KEY_ALIAS

当我尝试通过 fastlanejenkins 上构建我的项目时,出现以下错误:

* What went wrong:
Execution failed for task ':app:validateReleaseSigning'.
> Keystore file /Users/macmini/.jenkins/workspace/AndroidProject/app/$ANDROID_KEYSTORE not found for signing config 'release'.

另一件事,我在终端中有 env,它向我显示了所有系统环境变量,我定义的变量不在那里,所以我不完全确定 Jenkins 把它们放在哪里。我需要直接路径吗?那会是什么?

感谢任何帮助,谢谢!

这里是来自 Fabric 和 Fastlane 的 Mike。

我不相信这个:

ANDROID_KEYSTORE=$ANDROID_KEYSTORE
ANDROID_STORE_PASSWORD=$ANDROID_STORE_PASSWORD
ANDROID_KEY_ALIAS=$ANDROID_KEY_ALIAS

将按照您希望的方式工作。如果您已经为环境变量设置了您想要的值,您可以在 build.gradle 中使用 String.valueOf(System.env.ANDROID_KEYSTORE) 等,并跳过在 gradle.properties 中放置任何其他内容。

假设您的问题是:"do I need a direct (or absolute) path (to the keystore)" 和 "what would that (path) be"。

我会回答 "no" 和 "it's likely to be the path shown in the last line of your log, but including the expansion of the variable $ANDROID_KEYSTORE"!

事实上,我遇到了你的问题,希望在 Jenkins GNU/Linux 奴隶上实现几乎相同的目标。

首先,我认为您面临的问题是那些环境变量不会从 gradle.properties 文件中展开! Groovy 有时是神奇的,所以我检查过以确保:它不会那样做,这解释了为什么你的密钥库路径错误(包含字符串“$ANDROID_KEYSTORE”而不是变量的值)。

要解决此问题,我看到两个选项:

  1. 您可以尝试配置您的 Jenkins 作业(可能需要预先执行步骤)以生成具有扩展值的 gradle.properties 文件:

    echo "ANDROID_KEYSTORE=${ANDROID_KEYSTORE}" >> gradle.properties

您甚至可以考虑按照建议使用特定的属性文件 here

  1. 在我看来,一个更灵活的选择是添加一些代码来尝试从环境中读取这些变量,然后使用如上所述的属性文件来定义默认值(如果某些开发人员拥有密钥并允许手动发布版本)。

我已经在 app/build.gradle:

中成功测试了类似的东西
// Load a specific properties file to access the keystore if exists
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file("keystore.properties")

if (keystorePropertiesFile.exists() ) {
    // Load keystore properties from file
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
} else {
    // Load keystore properties from environment or set their default values
    def env = System.getenv()
    if (env['ANDROID_KEYALIAS']) keystoreProperties.put('keyAlias', env['ANDROID_KEYALIAS'])
    else keystoreProperties.put('keyAlias', "myDefaultAlias")
    if (env['ANDROID_KEYPASSWORD']) keystoreProperties.put('keyPassword', env['ANDROID_KEYPASSWORD'])
    else keystoreProperties.put('keyPassword', "myDefaultKeyPass")
    if (env['ANDROID_STOREFILE']) keystoreProperties.put('storeFile', env['ANDROID_STOREFILE'])
    else keystoreProperties.put('storeFile', "./keystore.jks")
    if (env['ANDROID_STOREPASSWORD']) keystoreProperties.put('storePassword', env['ANDROID_STOREPASSWORD'])
    else keystoreProperties.put('storePassword', "myDefaultStorePass")
}

...

android {
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile file(keystoreProperties['storeFile'])
            storePassword keystoreProperties['storePassword']
        }
    }

我相信这可以得到很多改进,并且可能会转而使用环境变量覆盖属性(如果存在)。但它今天对我有用。

这就是说,正如您提到的,如果您在 env 命令的输出中没有看到这些变量,您最好查找它们。我建议您使用 env 命令开始构建步骤。当然,在单独的终端中输入此命令不会向您显示 Jenkins 正在为该特定构建做什么。