groovy Android分级:在生成时动态更改versionName

k5hmc34c  于 2022-11-01  发布在  Android
关注(0)|答案(7)|浏览(173)

我正在尝试使用自定义版本的gradle-release插件来模拟Android中的Maven版本插件:https://github.com/townsfolk/gradle-release
有趣的步骤包括:

  • 检查未提交的更改
  • 单步执行版本代码并从版本名称中删除-SNAPSHOT后缀
  • 组建
  • 单步执行版本名称并为下一个开发版本添加-SNAPSHOT后缀

但是,生成的APK始终具有以前的版本(即1.0.0-SNAPSHOT,而不是1.0.0)。
版本号在www.example.com中存储并正确更新gradle.properties,因此我假设我还需要更新数据模型中的版本,以便更改生效。
我的Android插件配置:

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
    }
}

但我的应用程序中没有任何风格(仅限纯调试和发布构建类型)。
我的替代方法是编写一个bash/bat脚本,在调用Gradle之前逐步执行版本,这与使用Groovy改进构建定制的目的完全相反。
如何在执行阶段在Android Gradle插件中动态更新版本?

r7s23pms

r7s23pms1#

这就是buildTypes的用途。你所描述的是一个release版本,IMO。
下面是一个例子:当执行assembleDebug时,它会给予你一个快照版本,而执行assembleRelease会给你一个没有任何后缀和递增版本号的干净版本。下一个调试版本也会使用递增的版本号。
以下是在文件夹中创建文件时的完整功能构建。它也可以用于各种风格,但这只是附带产品:). Gradle 2.2.1,Android插件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()}"

Android系统的安全性

<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目录中生成的文件,查看值是否符合您的要求。

手动执行(来自注解)

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

gradle incrementVersion assembleFreeRelease assemblePaidRelease

(The上述手动执行是一个未经测试的想法。)

检查未提交的更改

“检查未提交的更改”不在这个答案中,这是另一个游戏。如果我理解正确的话,你可以挂到tasks.preBuild.doFirst { /*fail here if uncommited changes*/ }上。但这高度依赖于你的版本控制。问另一个问题以获得更多信息!

enxuqcxy

enxuqcxy2#

我需要把当前的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,你可以生成你自己的变量来定制版本名。因为我只是在执行一个终端命令,将其结果存储在一个变量中。

snvhrwxg

snvhrwxg3#

这并没有直接解决如何完全更改versionName的问题,但我使用以下代码为我的buildTypes追加后缀:

defaultConfig {
    versionName "1.0"
}

buildTypes {
    debug {
        versionNameSuffix "-SNAPSHOT"
    }
}
8qgya5xd

8qgya5xd4#

我只是使用了Javanator's answer并做了一些修改,这样commit count不仅可以帮助更改名称,还可以确保版本代码保持唯一性。下面是我所做的一个示例(也许有几件事可以优化,但仍然为我做了这项工作):

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"
            }
        }
    }
}
w1jd8yoj

w1jd8yoj5#

我也面临着类似的需求,即发布和非发布构建需要有独立的构建逻辑,除了不同的版本之外,我还必须使用不同的依赖关系,甚至是不同的存储库。
没有一个可用的插件具有我所需要的所有特性,所以我开发了我自己的解决方案,基于简单的方法-命令行参数。
您可以在调用gradle构建脚本时传递命令行参数,如下所示:

gradle build -PmyParameter=myValue

就我而言

gradle build -PisRelease=true

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

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

我将这个逻辑提取到一个单独的插件中,并且我已经成功地在不同的项目中使用了它。
虽然这不能直接回答你的问题,但我希望我给了你另一个Angular 来思考这个问题和另一个可能的解决方案。

wwwo4jvm

wwwo4jvm6#

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

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

x4shl7ld7#

版本名称和版本代码都可以动态生成,如下所示。

/**
 * computedVersionCode()
 * do not name this to getVersionCode. getVersionCode conflicts with the automatic getter of versionCode
 * version code is an int a value between 0 and max int value 2147483647 is expected.
 * This function returns at int in yyyMMddHH format
 * For example, 2022061121 for 11 June 2022 between 21:00 to 21:59
 * This gives a new versioncode for every different hour of day and same code within same hour of hour of day
 * Max int value is 2147483647. So after year 2147 it will overflow to -ve values.
 * max value in year 2147 will be 2147121223 so Lot of scope of manually incrementing up-to 2147483647  will be there.
 * @return an int corresponding to current hour in yyyyMMddHH format
 */
static def computedVersionCode() {

    def date = new Date()
    def formattedDate = date.format('yyyyMMddHH')
    int versionCodeInt = (int) Long.parseLong(formattedDate)
    return versionCodeInt
}

/**
 * computedVersionCode2()
 * do not name this to getVersionCode. getVersionCode conflicts with automatic getter of versionCode
 * version code is an int a value between 0 and Max int value 2147483647 is expected.
 * This function returns total hours since epoch
 * For example, it returns 459711 for 11 June 2022 at 21:21 IST
 * This gives a new versioncode for every different hour
 * Max int value is 2147483647. This format is good till 09-Oct-246953 12:30:00 PM
 *
 * @return hours since epoch which can be used as version code
 */
static def computedVersionCode2() {

    long millisSinceEpoch = System.currentTimeMillis();
    long hoursSinceEpoch = millisSinceEpoch/(3600*1000);
    int hoursSinceEpochInt = (int)hoursSinceEpoch;

    //Hours since epoch changes every hour automatically.
    //If data type int remains of same size forever this value will be good till year 4419.

    return hoursSinceEpochInt;
}

static def computedVersionSuffix() {
    def date = new Date()
    def formattedDate = date.format('yyyyMMdd.HH.mm')
    return formattedDate
}

android {
    compileSdkVersion 32
    defaultConfig {
       ...
        versionCode computedVersionCode()
        versionName "1.0.8.".concat(computedVersionSuffix())
       ....
    }

相关问题