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

时间:2023-02-12
本文介绍了Android Gradle:在构建时动态更改版本名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to emulate Maven release plugin in Android by using a customized version of gradle-release plugin: https://github.com/townsfolk/gradle-release

有趣的步骤是:

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

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

However the generated APK always has the previous versions (i.e. 1.0.0-SNAPSHOT instead of 1.0.0).

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

Version numbers are stored and correctly updated in gradle.properties, so I'm assuming that I need to update the versions in the data model as well for the changes to take effect.

我的安卓插件配置:

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.

But there's no versionName in a variant.

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

但类型中没有 versionName.

But there's no versionName in a type.

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

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

But there are no flavors in my app (plain debug and release build types only).

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

My alternative is to write a bash/bat script to step the versions before invoking Gradle, which pretty much defeats the purpose of using Groovy to improve build customization.

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

How can I update versions dynamically in the Android Gradle plugin in the execution phase?

推荐答案

这就是 buildTypes 的用途.你所描述的是一个 release 构建,IMO.

That's what buildTypes are for. What you're describing is a release build, IMO.

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

Here's an example: when executing assembleDebug it will give you a snapshot build, and executing assembleRelease will give you a clean build without any suffix and incremented version number. The next debug build will also use the incremented number.

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

The following is a fully functional build when the files are created in a folder. It should also work with flavors, but that's just a side product :). Gradle 2.2.1, Android plugin 1.1.3

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的顺序会产生不同的结果.

Execute gradle assembleDebug to build normally, gradle assembleRelease to increment and build, and gradle incrementVersion to just increment. Note: be careful with gradle assemble because the order of assembleDebug and assembleRelease will yield different results.

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

Check the generated files in the build directory to see if the values are to your liking.

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

It is possible you have multiple flavors in which case the version is incremented multiple times because multiple variants match the release build type. The original quesion was for no flavors. If you want to have more control when the version number is incremented just remove the afterEvaluate block and call the incrementVersion task whenever you want:

gradle incrementVersion assembleFreeRelease assemblePaidRelease

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

(The above manual execution is an untested idea.)

此答案未涵盖检查未提交的更改",这是另一个游戏.如果我理解正确,您可以连接到 tasks.preBuild.doFirst {/*fail here if uncommited changes*