Android Gradle:在构建时动态更改版本名称

Posted

技术标签:

【中文标题】Android Gradle:在构建时动态更改版本名称【英文标题】:Android Gradle: Dynamically change versionName at build time 【发布时间】:2014-02-20 06:30:43 【问题描述】:

我正在尝试使用自定义版本的 gradle-release 插件在 android 中模拟 Maven 发布插件:https://github.com/townsfolk/gradle-release

有趣的步骤是:

检查未提交的更改 步骤版本代码并删除 -SNAPSHOT 版本名称的后缀 构建 步骤版本名称并添加-SNAPSHOT 下一个开发版本的后缀

但是生成的 APK 始终具有以前的版本(即 1.0.0-SNAPSHOT 而不是 1.0.0)。

版本号在 gradle.properties 中存储并正确更新,因此我假设我需要更新数据模型中的版本以及更改才能生效。

我的安卓插件配置:

defaultConfig 
    versionCode versionCode as int  // taken from gradle.properties
    versionName versionName // taken from gradle.properties
    minSdkVersion 10
    targetSdkVersion 19

我尝试过的事情:

preBuild << 
    android.applicationVariants.each  variant ->
        variant.versionName = versionName
    

但变体中没有 versionName。

preBuild << 
    android.buildTypes.each  type ->
        type.versionName = versionName
    

但类型中没有 versionName。

preBuild << 
    android.productFlavors.each  flavor ->
        flavor.versionName = versionName
    

但我的应用中没有任何风格(仅限普通调试和发布构建类型)。

我的替代方法是在调用 Gradle 之前编写一个 bash/bat 脚本来步进版本,这几乎违背了使用 Groovy 改进构建自定义的目的。

如何在Android Gradle插件的执行阶段动态更新版本?

【问题讨论】:

我在***.com/questions/24818755/… 发帖后发现了你的问题,你找到解决方案了吗? 抱歉,我最终编写了更改版本的 bash/bat 脚本,现在我需要维护 Windows 和 Unix 特定代码:( 哈哈,我也创建了自定义脚本,但是我把它们写成 Gradle 任务,所以它们是跨平台的 :) variant.mergedFlavor 是你所需要的 【参考方案1】:

这就是buildTypes 的用途。您所描述的是 release 构建,IMO。

这是一个例子:当执行assembleDebug 时,它会给你一个快照构建,执行assembleRelease 会给你一个干净的构建,没有任何后缀和递增的版本号。下一个调试版本也将使用递增的数字。

以下是在文件夹中创建文件时功能齐全的构建。它也应该适用于口味,但这只是一个副产品:)。 Gradle 2.2.1,Android 插件 1.1.3

build.gradle

apply plugin: 'com.android.application'
apply from: 'auto-version.gradle'

buildscript 
    repositories  jcenter() 
    dependencies  classpath 'com.android.tools.build:gradle:1.1.3' 


android 
    buildToolsVersion = "21.1.2"
    compileSdkVersion = "android-21"

    buildTypes 
        debug 
            versionNameSuffix "-SNAPSHOT"
        
    


println "config code: $calculateVersionCode(), name: $calculateVersionName()"

src/main/AndroidManifest.xml

<manifest package="com.example" />

自动版本.gradle

ext 
    versionFile = new File(project.rootDir, 'version.properties')
    calculateVersionName = 
        def version = readVersion()
        return "$version['major'].$version['minor'].$version['build']"
    
    calculateVersionCode = 
        def version = readVersion()
        def major = version['major'] as int // 1..∞
        def minor = version['minor'] as int // 0..99
        def build = version['build'] as int // 0..999
        return (major * 100 + minor) * 1000 + build
    



Properties readVersion() 
    def version = new Properties()
    def stream
    try 
        stream = new FileInputStream(versionFile)
        version.load(stream)
     catch (FileNotFoundException ignore) 
     finally 
        if (stream != null) stream.close()
    
    // safety defaults in case file is missing
    if(!version['major']) version['major'] = "1"
    if(!version['minor']) version['minor'] = "0"
    if(!version['build']) version['build'] = "0"
    return version


void incrementVersionNumber() 
    def version = readVersion()

    // careful with the types, culprits: "9"++ = ":", "9" + 1 = "91"
    def build = version['build'] as int
    build++
    version['build'] = build.toString()

    def stream = new FileOutputStream(versionFile)
    try 
        version.store(stream, null)
     finally 
        stream.close()
    


task incrementVersion 
    description "Increments build counter in $versionFile"
    doFirst 
        incrementVersionNumber()
    


if (plugins.hasPlugin('android') || plugins.hasPlugin('android-library')) 
    android 
        defaultConfig 
            versionName = calculateVersionName()
            versionCode = calculateVersionCode()
        

        afterEvaluate 
            def autoIncrementVariant =  variant ->
                if (variant.buildType.name == buildTypes.release.name)  // don't increment on debug builds
                    variant.preBuild.dependsOn incrementVersion
                    incrementVersion.doLast 
                        variant.mergedFlavor.versionName = calculateVersionName()
                        variant.mergedFlavor.versionCode = calculateVersionCode()
                    
                
            
            if (plugins.hasPlugin('android')) 
                applicationVariants.all  variant -> autoIncrementVariant(variant) 
            
            if (plugins.hasPlugin('android-library')) 
                libraryVariants.all  variant -> autoIncrementVariant(variant) 
            
        
    

执行gradle assembleDebug 正常构建,gradle assembleRelease 递增和构建,gradle incrementVersion 只是递增。 注意:注意gradle assemble,因为assembleDebugassembleRelease 的顺序会产生不同的结果。

检查build 目录中生成的文件,看看这些值是否符合您的喜好。

手动执行(来自 cmets)

您可能有多种风格,在这种情况下版本会多次递增,因为多个变体与发布构建类型匹配。最初的问题是没有味道。如果您想在版本号增加时拥有更多控制权,只需删除 afterEvaluate 块并随时调用 incrementVersion 任务:

gradle incrementVersion assembleFreeRelease assemblePaidRelease

(上述手动执行是一个未经验证的想法。)

检查未提交的更改

此答案未涵盖“检查未提交的更改”,这是另一个游戏。如果我理解正确,您可以联系tasks.preBuild.doFirst /*fail here if uncommited changes*/ 。但这在很大程度上取决于您的版本控制。询问其他问题以获得更多信息!

【讨论】:

虽然我不确定这是否是问题细节的最佳答案,但它回答了标题,以及从谷歌把我带到这里的问题,所以我会给你一个赞成票. 这仅部分有效。版本是从文件中读取的,但从不增加!我登录并看到从未调用过incrementVersionNumber()。无论出于何种原因,检查if (variant.buildType == buildTypes.release) 似乎都不是真的。用if (variant.name == "release") 替换它对我有用。 @Dadou 感谢提醒,我更新了最新版本的答案并修复了它。他们在 0.14.x 左右引入了只读 buildTypes,似乎这两个只读包装器是分开创建的。 @WOLVERINE 您可以从readVersion 方法源中看到格式。运行 gradle incrementVersion 也会为您创建文件。 @meeDamian 此代码始终递增 versionCode,因为它始终遍历每个构建变体。为了阻止它,我将此功能 boolean isRelease() def runTasks = gradle.startParameter.taskNames return ('assemble' in runTasks || 'assembleRelease' in runTasks) variant.buildType.name == buildTypes.release.name 结合使用【参考方案2】:

我需要将代码修订的当前 git 提交计数附加到版本名称。它在许多情况下都非常方便。我最终得到了以下简单的 gradle 文件

apply plugin: 'com.android.application'

android 
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    def gitCommitCount = "git rev-list HEAD --count".execute().text.trim()

    defaultConfig 
        applicationId "my.app.package.name"
        minSdkVersion 16
        targetSdkVersion 21
        versionCode 6
        versionName "0.8"
    

    buildTypes 

        debug 
            versionNameSuffix ".$gitCommitCount"
        

        release 
            versionNameSuffix ".$gitCommitCount"
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        
    

与 gitCommitCount 类似,您可以生成自己的变量来自定义版本名称。因为我只是在执行一个终端命令以将其结果存储在一个变量中。

【讨论】:

好主意。我现在通过获取所有分支的提交计数并转换为 int 来为 versionCode 使用 git commit number:def gitCommitCount = "git rev-list --all --count".execute().text.trim().toInteger()【参考方案3】:

这并不能直接解决您关于如何完全更改 versionName 的问题,但这是我用来为我的 buildTypes 附加后缀的方法:

defaultConfig 
    versionName "1.0"


buildTypes 
    debug 
        versionNameSuffix "-SNAPSHOT"
    

【讨论】:

是的,我知道,但是versionNameSuffix 在任何 gradle 任务之前初始化,所以你不能从某些任务中改变它:( 这正是我一直在寻找的,将 DEBUG 附加到我的调试版本以保持我的日志干净。发送!【参考方案4】:

我刚刚使用了Javanator's answer 并对其进行了一些修改,以便提交计数不仅有助于更改名称,而且确保版本代码也保持唯一。这是我所做的一个示例(也许可以优化一些事情,但仍然可以为我完成这项工作):

android 
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    def gitCommitCount = "git rev-list HEAD --count".execute().text.trim().toBigInteger()
    project.ext.set("versionCode", gitCommitCount)
    project.ext.set("versionNameSuffix", "($gitCommitCount)")

    defaultConfig 
        applicationId "my.app.package.name"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode  project.versionCode
        versionName "1.0"
        versionNameSuffix project.versionNameSuffix
        setProperty("archivesBaseName", "MyProject-$versionName")
        ....
    

    signingConfigs 
        config 
            .........
        
    

    buildTypes 
        release 
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config
        
    

    packagingOptions 
        .....
    

    applicationVariants.all  variant ->
        variant.outputs.each  output ->
            output.outputFile = new File(
                    output.outputFile.parent,
                    output.outputFile.name.replace(".apk", "-$variant.versionName.apk"))
        
    

编辑: 最后一点也可以是

    applicationVariants.all  variant ->
    if (variant.name.contains('release')) 
        variant.outputs.each  output ->
            variant.outputs.all 
                outputFileName = "MyProject-$variant.versionName$variant.versionCode.apk"
            
        
    

【讨论】:

【参考方案5】:

我也面临着类似的需求,即为发布和非发布构建提供单独的构建逻辑。 除了不同的版本控制之外,我还必须使用一组不同的依赖项,甚至是不同的存储库。

所有可用的插件都没有我需要的所有功能,所以我开发了自己的解决方案,基于简单的方法 - 命令行参数。

在调用 gradle build 脚本时可以像这样传递命令行参数:

gradle build -PmyParameter=myValue

或者在我的情况下

gradle build -PisRelease=true

Gradle 会解析它,它会自动作为项目对象的属性使用。 然后你可以像这样使用它:

if (project.hasProperty('isRelease') && project.isRelease) 
        // Here be the logic!

我将这个逻辑提取到一个单独的插件中,并且我已经成功地在不同的项目中使用它。

虽然这并不能直接回答你的问题,但我希望我能给你另一个角度来思考这个问题和另一个可能的解决方案。

【讨论】:

这可以很容易地与我的答案中的incrementVersionNumber() 方法结合使用!我也用它,你甚至可以有条件地在 settings.gradle 中包含模块。【参考方案6】:

这个问题迟到了,但您可以尝试以下方法将动态构建后缀附加到 versionName 中的 build.gradle

def buildCode = (int)(((new Date().getTime()/1000) - 1451606400) / 10)
android 
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig 
        ...
        versionName "0.1.$buildCode"
        ...
    

【讨论】:

以上是关于Android Gradle:在构建时动态更改版本名称的主要内容,如果未能解决你的问题,请参考以下文章

在构建 gradle 和提交中更改版本代码后,不使用 devops Pipeline 生成 Android APK 版本明智

Android编译gradle 动态修改版本号

Android Studio Gradle 版本不同报错解决方法

Android Gradle 插件Gradle 依赖管理 ⑤ ( dependencies 依赖项拆分 | 依赖组 | 依赖名称 | 依赖版本号 | 动态指定依赖版本号 | 使用命令行查看模块 )

Android Gradle 构建:重命名 apk

很长的 gradle 构建时间 - Android