Android 具有 gradle 额外属性的自动增量 VersionCode

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21405457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:31:53  来源:igfitidea点击:

Autoincrement VersionCode with gradle extra properties

androidgradleandroid-gradle-pluginbuild.gradle

提问by carvaq

I'm building an Android app with gradle. Until now I used the Manifest file to increase the versionCode, but I would like to read the versionCode from an external file and depending if it is the release flavor or the debug flavor increase the versionCode. I tried the extra properties, but you can't save them, which means that next time I build it I'm getting the same versionCode. Any help would be very much appreciated!

我正在用 gradle 构建一个 Android 应用程序。到目前为止,我使用 Manifest 文件来增加 versionCode,但我想从外部文件中读取 versionCode,并根据它是发布风格还是调试风格来增加 versionCode。我尝试了额外的属性,但您无法保存它们,这意味着下次构建它时我会得到相同的 versionCode。任何帮助将不胜感激!

project.ext{
    devVersionCode = 13
    releaseVersionCode = 1
}

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.6.+'
    }
}

apply plugin: 'android'

repositories {
    mavenCentral()
}

dependencies {
    compile project(':Cropper')
    compile "com.android.support:appcompat-v7:18.0.+"
    compile "com.android.support:support-v4:18.0.+"
    compile fileTree(dir: 'libs', include: '*.jar')
}

def getReleaseVersionCode() {
    def version = project.releaseVersionCode + 1
    project.releaseVersionCode = version
    println sprintf("Returning version %d", version)
    return version
}

def getDevVersionCode() {
    def version = project.devVersionCode + 1
    project.devVersionCode = version
    println sprintf("Returning version %d", version)
    return version
}


def getLastVersioName(versionCode) {
    return "0.0." + versionCode
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 19
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
    }

    buildTypes {
        release {
            runProguard true
            proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
            proguardFile 'proguard.cfg'
            debuggable false
            signingConfig null
            zipAlign false
        }
        debug {
            versionNameSuffix "-DEBUG"
        }
    }
    productFlavors {
        dev {
            packageName = 'com.swisscom.docsafe.debug'
            versionCode getDevVersionCode()
            versionName getLastVersioName(project.devVersionCode)
        }
        prod {
            packageName = 'com.swisscom.docsafe'
            versionCode getReleaseVersionCode()
            versionName getLastVersioName(project.releaseVersionCode)
        }
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.8'
}

回答by CommonsWare

I would like to read the versionCode from an external file

我想从外部文件中读取 versionCode

I am sure that there are any number of possible solutions; here is one:

我相信有许多可能的解决方案;这是一个:

android {
    compileSdkVersion 18
    buildToolsVersion "18.1.0"

    def versionPropsFile = file('version.properties')

    if (versionPropsFile.canRead()) {
        def Properties versionProps = new Properties()

        versionProps.load(new FileInputStream(versionPropsFile))

        def code = versionProps['VERSION_CODE'].toInteger() + 1

        versionProps['VERSION_CODE']=code.toString()
        versionProps.store(versionPropsFile.newWriter(), null)

        defaultConfig {
            versionCode code
            versionName "1.1"
            minSdkVersion 14
            targetSdkVersion 18
        }
    }
    else {
        throw new GradleException("Could not read version.properties!")
    }

    // rest of android block goes here
}

This code expects an existing version.propertiesfile, which you would create by hand before the first build to have VERSION_CODE=8.

此代码需要一个现有version.properties文件,您将在第一次构建之前手动创建该文件,该文件具有VERSION_CODE=8.

This code simply bumps the version code on each build -- you would need to extend the technique to handle your per-flavor version code.

这段代码只是在每次构建时修改版本代码——您需要扩展该技术来处理您的每个风格的版本代码。

You can see the Versioning sample projectthat demonstrates this code.

您可以查看演示此代码的版本控制示例项目

回答by just_user

Here comes a modernization of my previous answer which can be seen below. This one is running with Gradle 4.4and Android Studio 3.1.1.

这是我以前的答案的现代化,可以在下面看到。这个是在Gradle 4.4Android Studio 3.1.1 上运行的

What this script does:

这个脚本的作用:

  • Creates a version.propertiesfile if none exists (up vote Paul Cantrell's answer below, which is where I got the idea from if you like this answer)
  • For each build, debug release or any time you press the run button in Android Studio the VERSION_BUILD number increases.
  • Every time you assemble a release your Android versionCodefor the play store increases and your patch numberincreases.
  • Bonus: After the build is done copies your apk to projectDir/apkto make it more accessible.
  • 如果不存在,则创建一个version.properties文件(对下面 Paul Cantrell 的回答投上一票,如果你喜欢这个答案,我就是从这里得到这个想法的)
  • 对于每个构建、调试版本或任何时候在 Android Studio 中按下运行按钮,VERSION_BUILD 数字都会增加。
  • 每次您组装一个发行版时,您的 Play 商店的Android版本代码都会增加,并且您的补丁号也会增加。
  • 奖励:构建完成后,将您的 apk 复制到projectDir/apk以使其更易于访问。

This script will create a version number which looks like v1.3.4 (123)and build an apk file like AppName-v1.3.4.apk.

此脚本将创建一个看起来像的版本号v1.3.4 (123)并构建一个类似AppName-v1.3.4.apk的 apk 文件。

Major version ?       ? Build version
             v1.3.4 (123)
  Minor version ?|? Patch version

Major version:Has to be changed manually for bigger changes.

主要版本:必须手动更改以进行更大的更改。

Minor version:Has to be changed manually for slightly less big changes.

次要版本:必须手动更改以进行较小的更改。

Patch version:Increases when running gradle assembleRelease

补丁版本:运行时增加gradle assembleRelease

Build version:Increases every build

构建版本:增加每次构建

Version Number:Same as Patch version, this is for the version code which Play Store needs to have increased for each new apk upload.

版本号:Patch version相同,这是 Play Store 需要为每个新的 apk 上传增加的版本代码。

Just change the content in the comments labeled 1 - 3 below and the script should do the rest. :)

只需更改下面标记为 1 - 3 的注释中的内容,脚本就可以完成剩下的工作。:)

android {
    compileSdkVersion 27
    buildToolsVersion '27.0.3'

    def versionPropsFile = file('version.properties')
    def value = 0
    Properties versionProps = new Properties()
    if (!versionPropsFile.exists()) {
        versionProps['VERSION_PATCH'] = "0"
        versionProps['VERSION_NUMBER'] = "0"
        versionProps['VERSION_BUILD'] = "-1" // I set it to minus one so the first build is 0 which isn't super important. 
        versionProps.store(versionPropsFile.newWriter(), null)
    }

    def runTasks = gradle.startParameter.taskNames
    if ('assembleRelease' in runTasks) {
        value = 1
    }

    def mVersionName = ""
    def mFileName = ""

    if (versionPropsFile.canRead()) {
        versionProps.load(new FileInputStream(versionPropsFile))

        versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
        versionProps['VERSION_NUMBER'] = (versionProps['VERSION_NUMBER'].toInteger() + value).toString()
        versionProps['VERSION_BUILD'] = (versionProps['VERSION_BUILD'].toInteger() + 1).toString()

        versionProps.store(versionPropsFile.newWriter(), null)

        // 1: change major and minor version here
        mVersionName = "v1.0.${versionProps['VERSION_PATCH']}"
        // 2: change AppName for your app name
        mFileName = "AppName-${mVersionName}.apk"

        defaultConfig {
            minSdkVersion 21
            targetSdkVersion 27
            applicationId "com.example.appname" // 3: change to your package name
            versionCode versionProps['VERSION_NUMBER'].toInteger()
            versionName "${mVersionName} Build: ${versionProps['VERSION_BUILD']}"
        }

    } else {
        throw new FileNotFoundException("Could not read version.properties!")
    }

    if ('assembleRelease' in runTasks) {
        applicationVariants.all { variant ->
            variant.outputs.all { output ->
                if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
                    outputFileName = mFileName
                }
            }
        }
    }

    task copyApkFiles(type: Copy){
        from 'build/outputs/apk/release'
        into '../apk'
        include mFileName
    }

    afterEvaluate {
        assembleRelease.doLast {
            tasks.copyApkFiles.execute()
        }
    }

    signingConfigs {
        ...
    }

    buildTypes {
        ...
    }
}

====================================================

================================================== ==

INITIAL ANSWER:

初始答案:

I want the versionName to increase automatically as well. So this is just an addition to the answer by CommonsWare which worked perfectly for me. This is what works for me

我也希望 versionName 自动增加。所以这只是对 CommonsWare 的回答的补充,它对我来说非常有用。这对我有用

defaultConfig {
    versionCode code
    versionName "1.1." + code
    minSdkVersion 14
    targetSdkVersion 18
}

EDIT:

编辑:

As I am a bit lazy I want my versioning to work as automatically as possible. What I want is to have a Build Versionthat increases with each build, while the Version Numberand Version Nameonly increases when I make a release build.

由于我有点懒惰,我希望我的版本控制尽可能自动地工作。我想要的是有一个随每次构建而增加的构建版本,而版本号版本名称仅在我进行发布构建时增加。

This is what I have been using for the past year, the basics are from CommonsWare's answer and my previous answer, plus some more. This results in the following versioning:

这是我过去一年一直在使用的内容,基础知识来自 CommonsWare 的答案和我之前的答案,以及更多内容。这导致以下版本控制:

Version Name: 1.0.5 (123)--> Major.Minor.Patch (Build), Major and Minor are changed manually.

版本名称:1.0.5 (123)--> Major.Minor.Patch (Build),Major 和 Minor 手动更改。

In build.gradle:

在 build.gradle 中:

...
android {
    compileSdkVersion 23
    buildToolsVersion '23.0.1'
    def versionPropsFile = file('version.properties')
    if (versionPropsFile.canRead()) {
        def Properties versionProps = new Properties()

        versionProps.load(new FileInputStream(versionPropsFile))

        def value = 0

        def runTasks = gradle.startParameter.taskNames
        if ('assemble' in runTasks || 'assembleRelease' in runTasks || 'aR' in runTasks) {
            value = 1;
        }

        def versionMajor = 1
        def versionMinor = 0
        def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value
        def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
        def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value

        versionProps['VERSION_PATCH'] = versionPatch.toString()
        versionProps['VERSION_BUILD'] = versionBuild.toString()
        versionProps['VERSION_NUMBER'] = versionNumber.toString()

        versionProps.store(versionPropsFile.newWriter(), null)

        defaultConfig {
            versionCode versionNumber
            versionName "${versionMajor}.${versionMinor}.${versionPatch} (${versionBuild}) Release"
            minSdkVersion 14
            targetSdkVersion 23
        }

        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                def fileNaming = "apk/RELEASES"
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        output.outputFile = new File(getProject().getRootDir(), "${fileNaming}-${versionMajor}.${versionMinor}.${versionPatch}-${outputFile.name}")
                    }
                }
            }
        }

    } else {
        throw new GradleException("Could not read version.properties!")
    }

    ...
}

...

Patch and versionCode is increased if you assemble your project through the terminal with 'assemble', 'assembleRelease'or 'aR'which creates a new folder in your project root called apk/RELEASE so you don't have to look through build/outputs/more/more/more to find your apk.

如果您使用'assemble''assembleRelease''aR'通过终端组装项目,则补丁和版本代码会增加,这会在项目根目录中创建一个名为 apk/RELEASE 的新文件夹,因此您不必查看构建/输出/more/more/more 找到您的 apk。

Your version properties would need to look like this:

您的版本属性需要如下所示:

VERSION_NUMBER=1
VERSION_BUILD=645
VERSION_PATCH=1

Obviously start with 0. :)

显然是从 0 开始的。:)

回答by Paul Cantrell

A slightly tightened-up version of CommonsWare's excellent answer creates the version file if it doesn't exist:

如果版本文件不存在,CommonsWare 的优秀答案的稍微收紧的版本会创建版本文件:

def Properties versionProps = new Properties()
def versionPropsFile = file('version.properties')
if(versionPropsFile.exists())
    versionProps.load(new FileInputStream(versionPropsFile))
def code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1
versionProps['VERSION_CODE'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)

defaultConfig {
    versionCode code
    versionName "1.1"
    minSdkVersion 14
    targetSdkVersion 18
}

回答by emmby

I looked at a few options to do this, and ultimately decided it was simpler to just use the current time for the versionCode instead of trying to automatically increment the versionCode and check it into my revision control system.

我查看了几个选项来执行此操作,最终决定只使用当前时间作为 versionCode,而不是尝试自动增加 versionCode 并将其签入我的修订控制系统更简单。

Add the following to your build.gradle:

将以下内容添加到您的build.gradle:

/**
 * Use the number of seconds/10 since Jan 1 2016 as the versionCode.
 * This lets us upload a new build at most every 10 seconds for the
 * next 680 years.
 */
def vcode = (int)(((new Date().getTime()/1000) - 1451606400) / 10)

android {
    defaultConfig {
        ...
        versionCode vcode
    }
}

However, if you expect to upload builds beyond year 2696, you may want to use a different solution.

但是,如果您希望上传 2696 年以后的版本,您可能需要使用不同的解决方案。

回答by C0D3LIC1OU5

Another way of getting a versionCodeautomatically is setting versionCodeto the number of commits in the checked out gitbranch. It accomplishes following objectives:

另一种versionCode自动获取 a 的方法是设置versionCode签出git分支中的提交次数。它实现了以下目标:

  1. versionCodeis generated automatically and consistently on any machine (including a Continuous Integrationand/or Continuous Deploymentserver).
  2. App with this versionCodeis submittable to GooglePlay.
  3. Doesn't rely on any files outside of repo.
  4. Doesn't push anything to the repo
  5. Can be manually overridden, if needed
  1. versionCode在任何机器(包括Continuous Integration和/或Continuous Deployment服务器)上自动且一致地生成。
  2. 具有此versionCode功能的应用可提交至 GooglePlay。
  3. 不依赖于 repo 之外的任何文件。
  4. 不会将任何内容推送到 repo
  5. 如果需要,可以手动覆盖

Using gradle-gitlibrary to accomplish the above objectives. Add code below to your build.gradlefile the /appdirectory:

使用gradle-git库来完成上述目标。将以下代码添加到您的build.gradle文件/app目录中:

import org.ajoberstar.grgit.Grgit

repositories {
    mavenCentral()
}

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'org.ajoberstar:grgit:1.5.0'
    }
}

android {
/*
    if you need a build with a custom version, just add it here, but don't commit to repo,
    unless you'd like to disable versionCode to be the number of commits in the current branch.

    ex. project.ext.set("versionCodeManualOverride", 123)
*/
    project.ext.set("versionCodeManualOverride", null)

    defaultConfig {
        versionCode getCustomVersionCode()
    }
}

def getCustomVersionCode() {

    if (project.versionCodeManualOverride != null) {
        return project.versionCodeManualOverride
    }

    // current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
    // above.
    ext.repo = Grgit.open(project.file('..'))

    // should result in the same value as running
    // git rev-list <checked out branch name> | wc -l
    def numOfCommits = ext.repo.log().size()
    return numOfCommits
}

NOTE: For this method to work, it's best to only deploy to Google Play Store from the same branch (ex. master).

注意:要使此方法起作用,最好仅从同一分支(例如master)部署到 Google Play 商店。

回答by moallemi

Recently I was working on a gradle plugin for Android that makes generating versionCodeand versionNameautomatically. there are lots of customization. here you can find more info about it https://github.com/moallemi/gradle-advanced-build-version

最近我正在为 Android 开发一个 gradle 插件,它可以自动生成versionCodeversionName。有很多定制。在这里你可以找到更多关于它的信息 https://github.com/moallemi/gradle-advanced-build-version

回答by carvaq

Another option, for incrementing the versionCodeand the versionName, is using a timestamp.

另一种用于增加versionCode和 的选项versionName是使用时间戳。

defaultConfig {
   versionName "${getVersionNameTimestamp()}"
   versionCode getVersionCodeTimestamp()
}


def getVersionNameTimestamp() {
    return new Date().format('yy.MM.ddHHmm')
}

def getVersionCodeTimestamp() {
    def date = new Date()
    def formattedDate = date.format('yyMMddHHmm')
    def code = formattedDate.toInteger()
    println sprintf("VersionCode: %d", code)
    return code
}

Starting on January,1 2022 formattedDate = date.format('yyMMddHHmm') exceeds the capacity of Integers

从 2022 年 1 月 1 日开始 formattedDate = date.format('yyMMddHHmm') 超出了整数的容量

回答by NickUnuchek

To increment versionCode only in release version do it:

要仅在发布版本中增加 versionCode,请执行以下操作:

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    def versionPropsFile = file('version.properties')
    def code = 1;
    if (versionPropsFile.canRead()) {
        def Properties versionProps = new Properties()

        versionProps.load(new FileInputStream(versionPropsFile))
        List<String> runTasks = gradle.startParameter.getTaskNames();
        def value = 0
        for (String item : runTasks)
        if ( item.contains("assembleRelease")) {
            value = 1;
        }
        code = Integer.parseInt(versionProps['VERSION_CODE']).intValue() + value
        versionProps['VERSION_CODE']=code.toString()
        versionProps.store(versionPropsFile.newWriter(), null)
    }
    else {
        throw new GradleException("Could not read version.properties!")
    }

    defaultConfig {
        applicationId "com.pack"
        minSdkVersion 14
        targetSdkVersion 21
        versionName "1.0."+ code
        versionCode code
    }

expects an existing c://YourProject/app/version.propertiesfile, which you would create by hand before the first build to have VERSION_CODE=8

需要一个现有c://YourProject/app/version.properties文件,您将在第一次构建之前手动创建该文件VERSION_CODE=8

File version.properties:

文件 version.properties

VERSION_CODE=8

VERSION_CODE=8

回答by Ahmad Aghazadeh

Create file version.properties

创建文件 version.properties

MAJOR=1
MINOR=3
PATCH=6
VERSION_CODE=1

Change build.gradle:

改变build.gradle

android {
def _versionCode=0
def _major=0
def _minor=0
def _patch=0

def _applicationId = "com.example.test"

def versionPropsFile = file('version.properties')

if (versionPropsFile.canRead()) {
    def Properties versionProps = new Properties()

    versionProps.load(new FileInputStream(versionPropsFile))

    _patch = versionProps['PATCH'].toInteger() + 1
    _major = versionProps['MAJOR'].toInteger()
    _minor = versionProps['MINOR'].toInteger() 
    _versionCode= versionProps['VERSION_CODE'].toInteger()+1
    if(_patch==99)
    {
        _patch=0
        _minor=_minor+1
    }
    if(_major==99){
        _major=0
        _major=_major+1
    }

    versionProps['MAJOR']=_major.toString()
    versionProps['MINOR']=_minor.toString()
    versionProps['PATCH']=_patch.toString()
    versionProps['VERSION_CODE']=_versionCode.toString()
    versionProps.store(versionPropsFile.newWriter(), null)
}
else {
    throw new GradleException("Could not read version.properties!")
}
def _versionName = "${_major}.${_versionCode}.${_minor}.${_patch}"


compileSdkVersion 23
buildToolsVersion "23.0.3"

defaultConfig {
    applicationId _applicationId
    minSdkVersion 11
    targetSdkVersion 23
    versionCode _versionCode
    versionName _versionName
}

}

}

Output : 1.1.3.6

输出 : 1.1.3.6

回答by Sergey Shustikov

Define versionNamein AndroidManifest.xml

定义的versionNameAndroidManifest.xml

android:versionName="5.1.5"

Inside android{...}block in build.gradleof app level :

应用程序级别的内部android{...}build.gradle

defaultConfig {
        applicationId "com.example.autoincrement"
        minSdkVersion 18
        targetSdkVersion 23
        multiDexEnabled true
        def version = getIncrementationVersionName()
        versionName version
}

Outside android{...}block in build.gradleof app level :

应用程序级别的外部android{...}build.gradle

def getIncrementedVersionName() {
    List<String> runTasks = gradle.startParameter.getTaskNames();

    //find version name in manifest
    def manifestFile = file('src/main/AndroidManifest.xml')
    def matcher = Pattern.compile('versionName=\"(\d+)\.(\d+)\.(\d+)\"').matcher(manifestFile.getText())
    matcher.find()

    //extract versionName parts
    def firstPart = Integer.parseInt(matcher.group(1))
    def secondPart = Integer.parseInt(matcher.group(2))
    def thirdPart = Integer.parseInt(matcher.group(3))

    //check is runTask release or not
    // if release - increment version
    for (String item : runTasks) {
        if (item.contains("assemble") && item.contains("Release")) {
            thirdPart++
            if (thirdPart == 10) {
                thirdPart = 0;
                secondPart++
                if (secondPart == 10) {
                    secondPart = 0;
                    firstPart++
                }
            }
        }
    }

    def versionName = firstPart + "." + secondPart + "." + thirdPart

    // update manifest
    def manifestContent = matcher.replaceAll('versionName=\"' + versionName + '\"')
    manifestFile.write(manifestContent)

    println "incrementVersionName = " + versionName

    return versionName
}

After create singed APK :

创建烧焦的 APK 后:

android:versionName="5.1.6"

Note : If your versionNamedifferent from my, you need change regexand extract parts logic.

注意:如果您的versionName与我的不同,需要更改正则表达式提取部分逻辑