Autoincrement VersionCode with gradle extra properties

前端 未结 16 2127
逝去的感伤
逝去的感伤 2020-11-27 08:47

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

相关标签:
16条回答
  • 2020-11-27 09:35

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

    What this script does:

    • Creates a version.properties file 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 versionCode for the play store increases and your patch number increases.
    • Bonus: After the build is done copies your apk to projectDir/apk to make it more accessible.

    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.

    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

    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.

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

    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

    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 Version that increases with each build, while the Version Number and Version Name only 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:

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

    In 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.

    Your version properties would need to look like this:

    VERSION_NUMBER=1
    VERSION_BUILD=645
    VERSION_PATCH=1
    

    Obviously start with 0. :)

    0 讨论(0)
  • 2020-11-27 09:35

    To increment versionCode only in release version do it:

    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.properties file, which you would create by hand before the first build to have VERSION_CODE=8

    File version.properties:

    VERSION_CODE=8

    0 讨论(0)
  • 2020-11-27 09:37

    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.

    Add the following to your 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.

    0 讨论(0)
  • 2020-11-27 09:37

    The First Commented code will increment the number while each "Rebuild Project" and save the the value in the "Version Property" file.

    The Second Commented code will generate new version name of APK file while "Build APKs".

    android {
        compileSdkVersion 28
        buildToolsVersion "29.0.0"
        //==========================START==================================
        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)
        //===========================END===================================
        defaultConfig {
            applicationId "com.example.myapp"
            minSdkVersion 15
            targetSdkVersion 28
            versionCode 1
            versionName "0.19"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
                //=======================================START===============================================
                android.applicationVariants.all { variant ->
                    variant.outputs.all {
                        def appName = "MyAppSampleName"
                        outputFileName = appName+"_v${variant.versionName}.${versionProps['VERSION_CODE']}.apk"
                    }
                }
                //=======================================END===============================================
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-27 09:38

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

    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
    }
    
    0 讨论(0)
  • 2020-11-27 09:38

    Another way of getting a versionCode automatically is setting versionCode to the number of commits in the checked out git branch. It accomplishes following objectives:

    1. versionCode is generated automatically and consistently on any machine (including a Continuous Integration and/or Continuous Deployment server).
    2. App with this versionCode is 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

    Using gradle-git library to accomplish the above objectives. Add code below to your build.gradle file the /app directory:

    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).

    0 讨论(0)
提交回复
热议问题