通过Gradle控制app版本

作者: 搬砖的兔子 | 来源:发表于2022-05-20 17:58 被阅读0次

前言


做过安卓开发的都知道,app版本控制主要依赖于两个参数versionName和versionCode,它们在我们项目模块的gradle文件中配置。而以往在做升级时,我们都是手动的去修改这两个参数。这在多人合作开发中是很不提倡的,因为往往较大的项目gradle文件经常要做修改替换,容易弄混,很不方便。
后来我们习惯将这两个参数的值提取出来,放在全局的配置文件gradle.properties中,然后在build.gradle中引用配置文件中定义的参数,从而确保版本控制参数从build.gradle中剥离。

//以下代码在根目录的gradle.properties中
VERSION_NAME = 1.0.0
VERSION_CODE = 1
//以下代码在build.gradle的android{}中配置
defaultConfig {
    ...
    versionCode Integer.parseInt(project.VERSION_CODE)
    versionName project.VERSION_NAME
    ...
}

还有种方式也是同样的思路,把版本号的配置单独的抽取出来的,放在单独的文件里,供build引用,就像我们在Android里,单独新建一个存放常量的Java类一样,供其他类调用。我们新建一个version.gradle文件并在其中添加以下代码。

ext{
    VERSION_NAME = 1.0.0
    VERSION_CODE = 1
}

然后在build.gradle中通过apply from:'version.gradle'来引用该模块,最后同上在build.gradle的android{}中配置即可。

其实以上几种方式都大同小异,都需要通过人为去修改参数从而控制版本号。那么有没有什么方式来自动控制版本号,实现版本自增的操作呢?接下来就让我们一起来实现它。

实现


第一步:在app模块的根目录下新建一个version.properties,并在其中添加如下key-value。
version_major=0
version_minor=0
version_patch=1
version_build=0
version_name=v_0.0.1
version_code=1

这里解释以下这几个参数:

参数 说明
version_major 主版本号,除非有重大更新一般不需要去修改它
version_minor 副版本号,小版本更新时去手动自增
version_patch 补丁版本号,每次build正式版时会自动加一
version_build build版本号,每次build测试版时会自增,正式发布时会置为0,并且不会带上此版本号
version_name 根据规则自动拼接组合,不需要手动修改
version_code 根据规则自动拼接组合,不需要手动修改
第二步:在app模块的build.gradle文件中定义如下方法实现文件读写操作。
//读取操作
static Properties readProperties(propertiesFile) {
    if (propertiesFile.canRead()) {  //判断文件是否可读
        Properties properties = new Properties()
        def inputStream = new FileInputStream(propertiesFile)
        properties.load(inputStream)
        inputStream.close()
        return properties
    } else {
        def message = "不能读取 " + propertiesFile.name + " 文件!"
        System.err.println(message)
        throw new GradleException(message)
    }
}

//写入操作
def static writeProperties(propertiesFile, properties) {
    def writer = propertiesFile.newWriter()
    //这里的desc是生成文件时的描述内容,可自己定义。
    def desc = "Automatic Properties\n" +
            "Please do not arbitrarily change the parameter values under this file\n" +
            "\t version_major: Major version number (manually modified when a major version is updated)\n" +
            "\t version_minor: Minor version number (manually modified when the minor version is updated, the value range is 0~99)\n" +
            "\t version_patch: Patch version number (automatically increase by 1 when the official version is released, please manually set 0 for modified size version, the value range is 0~999)\n" +
            "\t version_build: Test version number (informal version will be automatically added by one, official version will be automatically removed and set to 0)\n" +
            "\t version_name: Unmodifiable, automatically generated\n" +
            "\t version_code: Unmodifiable, automatically generated"
    properties.store(writer, desc)
    writer.close()
}
第三步:在app模块的build.gradle文件中定义如下方法来判断build操作是正式还是测试。
//判断是否为单元测试或debug包
def isTestTask() {
    def tasks = gradle.getStartParameter().getTaskNames()
    return ":app:testDebugUnitTest" in tasks || 
           "testDebugUnitTest" in tasks ||
           ":app:testReleaseUnitTest" in tasks || 
           "testReleaseUnitTest" in tasks ||
           ":app:assembleDebug" in tasks || 
           "assembleDebug" in tasks
}

//判断是否为正式包
def isReleaseTask() {
    def tasks = gradle.getStartParameter().getTaskNames()
    return ":app:assembleRelease" in tasks || 
           "assembleRelease" in tasks ||
           ":app:bundleRelease" in tasks || 
           "bundleRelease" in tasks
}
第四步:在app模块的build.gradle文件中定义如下方法实现版本控制(注意:这里生成的versionName和versionCode规则可以根据自己需求定)。
//自动更新版本信息
def updateVersion() {
    def propertiesFile = file("version.properties")
    Properties properties = readProperties(propertiesFile)

    def versionMajor = properties["version_major"].toString().toInteger()
    def versionMinor = properties["version_minor"].toString().toInteger()
    def versionPatch = properties["version_patch"].toString().toInteger()
    def versionBuild = properties["version_build"].toString().toInteger()

    if (isReleaseTask()) {    //正式版
        versionPatch++
        versionBuild = 0
    }
    if (isTestTask()) {       //测试版
        versionBuild++
    }
    def versionName = "v_${versionMajor}.${versionMinor}.${versionPatch}"
    def versionCode = versionMajor * 100000 + versionMinor * 1000 + versionPatch
    def applicationId = android.defaultConfig.applicationId
    if (!isReleaseTask()) {  //非正式包 加上build版本号
        versionName = versionName + ".${versionBuild}"
        applicationId = applicationId + "_"+android.buildTypes.debug.applicationIdSuffix 
    }
    properties["version_major"] = versionMajor.toString()
    properties["version_minor"] = versionMinor.toString()
    properties["version_patch"] = versionPatch.toString()
    properties["version_build"] = versionBuild.toString()
    properties["version_name"] = versionName.toString()
    properties["version_code"] = versionCode.toString()
    writeProperties(propertiesFile, properties)
    System.out.println(">>> " + project.parent.name + " " + versionName + " (" + versionCode + ") " + applicationId)
    //配置根据自己规则计算好的versionCode和versionName到defaultConfig中
    android.defaultConfig.versionCode = versionCode
    android.defaultConfig.versionName = versionName
}
第五步:在app模块的build.gradle文件中android{}内合适的时机来调用此updateVersion()方法。
    updateVersion() //必须在修改打包文件包名之前调用
    //如果你需要修改打包后的文件名并带上versionName的话,则需要在其之前调用updateVersion()。
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            if (variant.buildType.name.equals('release')) {
                def releaseApkName = "_${defaultConfig.versionName}_" + 'release.apk'
                outputFileName = releaseApkName
            } else if (variant.buildType.name.equals("debug")) {
                def releaseApkName = "_${defaultConfig.versionName}_" + 'debug.apk'
                outputFileName = releaseApkName
            }
        }
    }

至此,一个自动版本控制的配置已经完成了,现在我们试试成果。

成果


首先我们来试试打一个测试包,看下我们的version.properties文件是否发生了变化。


测试包返图.jpg

可以看到当我们打测试包时,version_build会自动加一,且version_name的值会带上version_build,由于测试包不发布所以version_code不变。

接下来我们打个正式包看看。


正式包返图.jpg

可以看到当我们打正式包时,version_build会清0,且version_name的值不会带上version_build,正式包的version_patch会自增,所以version_code也变大了。

补充


这里的version_major和version_minor还是需要开发者手动维护的,您也可以根据自己的逻辑定义方法来达到这两个参数的自动控制。

相关文章

网友评论

    本文标题:通过Gradle控制app版本

    本文链接:https://www.haomeiwen.com/subject/wcmfprtx.html