美文网首页Jenkins社区我的收藏Android代码封装
玩转Jenkins - Android发布自动版本号

玩转Jenkins - Android发布自动版本号

作者: 小发条 | 来源:发表于2017-03-23 16:10 被阅读931次

    title: 玩转Jenkins - Android发布自动版本号
    date: 2016-10-31
    tags:

    • Jenkins
    • 软件测试
    • 持续集成
    • Android
      categories: 持续集成
      keywords: 持续集成,jenkins,ci,自动部署,android,自动化测试

    最近在统一Ios和Android的打包流程,希望能够通过Jenkins自动打包并分发,在Android部分的实施过程中,发现应用的版本号每次都需要人手工去维护,十分的不方便,于是在网上搜索了一番,找到了一个方案。

    背景

    Android 应用的版本管理是依赖 AndroidManifest.xml 中的两个属性:

    android:versionCode :版本号,是一个大于 0 的整数,相当于 Build Number,随着版本的更新,这个必须是递增的。大的版本号,覆盖更新小的版本号;
    android:versionName :版本名,是一个字符串,例如 "1.2.0" ,这个是给人看的版本名,系统并不关心这个值,但是合理的版本名,对后期的维护和 bug 修复也非常重要。
    在使用了 Android Studio 或者 Gradle 编译以后,我们通常是在 build.gradle 里面定义这两个值,如下:

    android {  
        ...
        defaultConfig {
            ...
            versionCode 1
            versionName "1.0"
        }
    }
    

    自动版本号

    可以使用 Gitcommit 的数量来作为版本号(versionCode)。方案如下:

    def cmd = 'git rev-list HEAD --first-parent --count'  
    def gitVersion = cmd.execute().text.trim().toInteger()
    
    android {  
      defaultConfig {
        versionCode gitVersion
      }
    }
    

    这里关键是这一行 git 命令 git rev-list HEAD --first-parent --count ,表示获取当前分支的 commit 数量。

    这是一个绝妙的方案。因为在项目开发中,我们的往 Git 库中提交的 Commit 的数量应该是只增不减的(当然,在极少的情况下有例外),而且对应 Commit 的数量直接对应代码当前的版本状态,只要你做了代码修改,版本号就应该增加。有些解决方案中,每次 Build 就会增加一次版本号,个人感觉并不合适,如果是相同的代码,发布出去版本号应该保持一致,而不在于你编译多少次。

    另外,有些人可能会担心,每次版本发布,可能会包含几百个新的 commit,这样的话 versionCode 会不会增长太快了,最后导致不够用了。其实,完全没有必要担心,versionCode 是 int 类型,最大值是 2^31-1 ,也就是 21 亿多,Android 源码中,改动最活跃的 framework/base 所有分支到目前为止也就 20 万多个 commit,所以完全够用了。

    自动版本名

    前面通过一条简单的命令实现了自动化的 versionCode ,现在我们看怎么自动化 versionName 。

    在正常的发布流程中,在发布新版本的时候,都会在版本库中打 tag。一般情况下,tag 名就是版本名,而且也建议这么做,因为如果某个版本出现 bug,也可以正好 checkout 这个 tag 来查看代码。所以,现在的问题就是怎么自动获得 git 库中最新的最新 tag?原来,git 早就提供了命令 git describe ,它的功能就是获取从当期 commit 到距离它最近的 tag 的描述。默认都是 annoted tag,如果要指所有的类型的 tag 的话,就加 --tags 参数。

    执行 git describe 的结果是: v1.1-1-gXXXXXX ,其中 1 表示当前代码距离最近的 tag v1.1 一个 commit,最新的 commit 的 id 是 XXXXXX 。

    可见, describe 命令很好的描述了当前的分支的版本状态,我们可以直接使用这个它的输出作为版本号。在 build.gradle 中的使用如下:

    def cmd = 'git describe --tags'  
    def version = cmd.execute().text.trim()
    
    android {  
      defaultConfig {
        versionName version
      }
    }
    

    这样就可以自动抽取 git 中的 tag 为版本名了。有些同学可能接受不了这样版本名字 v1.1-1-gXXXXXX ,这里也可以稍微做一些修改,使版本号更好看,如下:

    def pattern = "-(\\d+)-g"  
    def matcher = version =~ pattern
    
    if (matcher) {  
        version = version.substring(0, matcher.start()) + "." + matcher[0][1]
    } else {
        version = version + ".0"
    }
    

    这样的话,上面的版本名就变为了 v1.0.0 和 v1.1.1 了。

    优化

    前面的那篇文章中说了,为了尽可能减少 gradle 脚本的运算,提高开发速度,我们可以把这样的自动版本的计算放到 release 编译中去。最后的写法如下:

    def gitVersionCode() {  
        def cmd = 'git rev-list HEAD --first-parent --count'
        cmd.execute().text.trim().toInteger()
    }
    
    def gitVersionTag() {  
        def cmd = 'git describe --tags'
        def version = cmd.execute().text.trim()
    
        def pattern = "-(\\d+)-g"
        def matcher = version =~ pattern
    
        if (matcher) {
            version = version.substring(0, matcher.start()) + "." + matcher[0][1]
        } else {
            version = version + ".0"
        }
    
        return version
    }
    
    android {  
        compileSdkVersion 23
        buildToolsVersion "23.0.2"
    
        defaultConfig {
            applicationId "com.race604.example"
            minSdkVersion 15
            targetSdkVersion 23
            versionCode 1
            versionName '1.0'
        }
        buildTypes {
            debug {
                // 为了不和 release 版本冲突
                applicationIdSuffix ".debug"
            }
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    
        applicationVariants.all { variant ->
            if (variant.buildType.name.equals('release')) {
                variant.mergedFlavor.versionCode = gitVersionCode()
                variant.mergedFlavor.versionName = gitVersionTag()
            }
        }
    }
    

    至此,结合 git 和 gradle 我们就实现了自动版本号。

    原文地址:http://fatiao.site/jenkins_androidversion.html

    相关文章

      网友评论

      • kalshen:今天技术总监要求必须这么处理😊
        小发条:@吃蜗牛的鸟 :+1:

      本文标题:玩转Jenkins - Android发布自动版本号

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