Automatic versioning of Android build using git describe with Gradle

后端 未结 10 1905
醉酒成梦
醉酒成梦 2020-11-30 18:18

I have searched extensively, but likely due to the newness of Android Studio and Gradle. I haven\'t found any description of how to do this. I want to do basically exactly

相关标签:
10条回答
  • 2020-11-30 19:19

    If it can be of any help, I've set up an example Gradle script that uses Git tags and Git describe to achieve this. Here's the code (you can also find it here).

    1) First create a versioning.gradle file containing:

    import java.text.SimpleDateFormat
    
    /**
     * This Gradle script relies on Git tags to generate versions for your Android app
     *
     * - The Android version NAME is specified in the tag name and it's 3 digits long (example of a valid tag name: "v1.23.45")
     *   If the tag name is not in a valid format, then the version name will be 0.0.0 and you should fix the tag.
     *
     * - The Android version CODE is calculated based on the version name (like this: (major * 1000000) + (minor * 10000) + (patch * 100))
     *
     * - The 4 digits version name is not "public" and the forth number represents the number of commits from the last tag (example: "1.23.45.178")
     *
     */
    
    ext {
    
        getGitSha = {
            return 'git rev-parse --short HEAD'.execute().text.trim()
        }
    
        getBuildTime = {
            def df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'")
            df.setTimeZone(TimeZone.getTimeZone("UTC"))
            return df.format(new Date())
        }
    
        /**
         * Git describe returns the following: [GIT_TAG_NAME]-[BUILD_NUMBER]-[GIT_SHA]
         */
        getAndroidGitDescribe = {
            return "git -C ${rootDir} describe --tags --long".execute().text.trim()
        }
    
        /**
         * Returns the current Git branch name
         */
        getGitBranch = {
            return "git rev-parse --abbrev-ref HEAD".execute().text.trim()
        }
    
        /**
         * Returns the full version name in the format: MM.mm.pp.ccc
         *
         * The version name is retrieved from the tag name which must be in the format: vMM.mm.pp, example: "v1.23.45"
         */
        getFullVersionName = {
            def versionName = "0.0.0.0"
            def (tag, buildNumber, gitSha) = getAndroidGitDescribe().tokenize('-')
            if (tag && tag.startsWith("v")) {
                def version = tag.substring(1)
                if (version.tokenize('.').size() == 3) {
                    versionName = version + '.' + buildNumber
                }
            }
            return versionName
        }
    
        /**
         * Returns the Android version name
         *
         * Format "X.Y.Z", without commit number
         */
        getAndroidVersionName = {
            def fullVersionName = getFullVersionName()
            return fullVersionName.substring(0, fullVersionName.lastIndexOf('.'))
        }
    
        /**
         * Returns the Android version code, deducted from the version name
         *
         * Integer value calculated from the version name
         */
        getAndroidVersionCode = {
            def (major, minor, patch) = getAndroidVersionName().tokenize('.')
            (major, minor, patch) = [major, minor, patch].collect{it.toInteger()}
            return (major * 1000000) + (minor * 10000) + (patch * 100)
        }
    
        /**
         * Return a pretty-printable string containing a summary of the version info
         */
        getVersionInfo = {
            return "\nVERSION INFO:\n\tFull version name: " + getFullVersionName() +
                    "\n\tAndroid version name: " + getAndroidVersionName() +
                    "\n\tAndroid version code: " + getAndroidVersionCode() +
                    "\n\tAndroid Git branch: " + getGitBranch() +
                    "\n\tAndroid Git describe: " + getAndroidGitDescribe() +
                    "\n\tGit SHA: " + getGitSha() +
                    "\n\tBuild Time: " + getBuildTime() + "\n"
        }
    
        // Print version info at build time
        println(getVersionInfo());
    }
    

    2) Then edit your app/build.gradle to use it like this:

    import groovy.json.StringEscapeUtils;
    
    apply plugin: 'com.android.application' // << Apply the plugin
    
    android {
    
        configurations {
            // ...
        }
    
        compileSdkVersion 22
        buildToolsVersion "22.0.1"
    
        defaultConfig {
    
            minSdkVersion 17
            targetSdkVersion 22
    
            applicationId "app.example.com"
    
            versionCode getAndroidVersionCode() // << Use the plugin!
            versionName getAndroidVersionName() // << Use the plugin!
    
            // Build config constants
            buildConfigField "String", "GIT_SHA", "\"${getGitSha()}\""
            buildConfigField "String", "BUILD_TIME", "\"${getBuildTime()}\""
            buildConfigField "String", "FULL_VERSION_NAME", "\"${getVersionName()}\""
            buildConfigField "String", "VERSION_DESCRIPTION", "\"${StringEscapeUtils.escapeJava(getVersionInfo())}\""
        }
    
        signingConfigs {
            config {
                keyAlias 'MyKeyAlias'
                keyPassword 'MyKeyPassword'
                storeFile file('my_key_store.keystore')
                storePassword 'MyKeyStorePassword'
            }
        }
    
        buildTypes {
    
            debug {
                minifyEnabled false
                debuggable true
            }
    
            release {
                minifyEnabled true
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                signingConfig signingConfigs.config
                debuggable false
            }
    
        }
    
        productFlavors {
           // ...
        }
    
        dependencies {
            // ...
        }
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_7
            targetCompatibility JavaVersion.VERSION_1_7
        }
    }
    
    /**
     * Save a build.info file
     */
    task saveBuildInfo {
        def buildInfo = getVersionInfo()
        def assetsDir = android.sourceSets.main.assets.srcDirs.toArray()[0]
        assetsDir.mkdirs()
        def buildInfoFile = new File(assetsDir, 'build.info')
        buildInfoFile.write(buildInfo)
    }
    
    gradle.projectsEvaluated {
        assemble.dependsOn(saveBuildInfo)
    }
    

    The most important part is to apply the plugin

    apply plugin: 'com.android.application'
    

    And then use it for the android version name and code

    versionCode getAndroidVersionCode()
    versionName getAndroidVersionName()
    
    0 讨论(0)
  • 2020-11-30 19:20

    Another way, using Android Studio (Gradle): Check out this blog post: http://blog.android-develop.com/2014/09/automatic-versioning-and-increment.html

    Here's the implementation from the blog:

    android {
    defaultConfig {
    ...
        // Fetch the version according to git latest tag and "how far are we from last tag"
        def longVersionName = "git -C ${rootDir} describe --tags --long".execute().text.trim()
        def (fullVersionTag, versionBuild, gitSha) = longVersionName.tokenize('-')
        def(versionMajor, versionMinor, versionPatch) = fullVersionTag.tokenize('.')
    
        // Set the version name
        versionName "$versionMajor.$versionMinor.$versionPatch($versionBuild)"
    
        // Turn the version name into a version code
        versionCode versionMajor.toInteger() * 100000 +
                versionMinor.toInteger() * 10000 +
                versionPatch.toInteger() * 1000 +
                versionBuild.toInteger()
    
        // Friendly print the version output to the Gradle console
        printf("\n--------" + "VERSION DATA--------" + "\n" + "- CODE: " + versionCode + "\n" + 
               "- NAME: " + versionName + "\n----------------------------\n")
    ...
    }
    

    }

    0 讨论(0)
  • 2020-11-30 19:21

    Define simple function in gradle file:

    def getVersion(){
        def out = new ByteArrayOutputStream();
        exec {
            executable = 'git'
            args = ['describe', '--tags']
            standardOutput = out
        }
        return out.toString().replace('\n','')
    }
    

    Use it:

    project.version = getVersion()
    
    0 讨论(0)
  • 2020-11-30 19:22

    Yet another way:

    https://github.com/gladed/gradle-android-git-version is a new gradle plugin that calculates android-friendly version names and version codes automatically.

    It handles a lot of special cases that are not possible using the accepted solution:

    • version tags for multiple projects in the same repo
    • expanded version codes like 1002003 for 1.2.3
    • gradle tasks for easily extracting version info for CI tools
    • etc.

    Disclaimer: I wrote it.

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