以前看到一些自動(dòng)化版本號(hào)打包的文章。如果您的項(xiàng)目是用 Git 管理的,并且恰巧又是使用 Gradle 編譯(應(yīng)該絕大部分都是這樣的了吧?),本文試圖找到一種更加優(yōu)雅的自動(dòng)版本管理方法。
我們都知道,Android 應(yīng)用的版本管理是依賴(lài) AndroidManifest.xml 中的兩個(gè)屬性:
android:versionCode:版本號(hào),是一個(gè)大于 0 的整數(shù),相當(dāng)于 Build Number,隨著版本的更新,這個(gè)必須是遞增的。大的版本號(hào),覆蓋更新小的版本號(hào);
android:versionName:版本名,是一個(gè)字符串,例如 "1.2.0",這個(gè)是給人看的版本名,系統(tǒng)并不關(guān)心這個(gè)值,但是合理的版本名,對(duì)后期的維護(hù)和 bug 修復(fù)也非常重要。
在使用了 Android Studio 或者 Gradle 編譯以后,我們通常是在 build.gradle 里面定義這兩個(gè)值,如下:
android {
...
defaultConfig {
...
versionCode 1
versionName "1.0"
}
}
在這篇文章中 6 tips to speed up your Gradle build 發(fā)現(xiàn)了,可以使用 Git 中 commit 的數(shù)量來(lái)作為版本號(hào)(versionCode)。方案如下:
def cmd = 'git rev-list HEAD --count'
def gitVersion = cmd.execute().text.trim().toInteger()
android {
defaultConfig {
versionCode gitVersion
}
}
這里關(guān)鍵是這一行 git 命令 git rev-list HEAD --count,表示獲取當(dāng)前分支的 commit 數(shù)量。
注:謝謝 @zhangls 提醒。原文直接使用了 6 tips to speed up your Gradle build 中的命令
git rev-list HEAD --first-parent --count,也就是帶了--first-parent選項(xiàng)。發(fā)現(xiàn)使用此選項(xiàng)并不合理,比如 這篇文章 中提到的,first-parent 可能會(huì)出現(xiàn)不穩(wěn)定的情況,這就可能導(dǎo)致獲得的 commit 數(shù)量并不保證是遞增的。
這是一個(gè)絕妙的方案。因?yàn)樵陧?xiàng)目開(kāi)發(fā)中,我們的往 Git 庫(kù)中提交的 Commit 的數(shù)量應(yīng)該是只增不減的(當(dāng)然,在極少的情況下有例外),而且對(duì)應(yīng) Commit 的數(shù)量直接對(duì)應(yīng)代碼當(dāng)前的版本狀態(tài),只要你做了代碼修改,版本號(hào)就應(yīng)該增加。有些解決方案中,每次 Build 就會(huì)增加一次版本號(hào),個(gè)人感覺(jué)并不合適,如果是相同的代碼,發(fā)布出去版本號(hào)應(yīng)該保持一致,而不在于你編譯多少次。
另外,有些人可能會(huì)擔(dān)心,每次版本發(fā)布,可能會(huì)包含幾百個(gè)新的 commit,這樣的話 versionCode 會(huì)不會(huì)增長(zhǎng)太快了,后導(dǎo)致不夠用了。其實(shí),完全沒(méi)有必要擔(dān)心,versionCode 是 int 類(lèi)型,大值是 2^31-1,也就是 21 億多,Android 源碼中,改動(dòng)活躍的 framework/base 所有分支到目前為止也就 20 萬(wàn)多個(gè) commit,所以完全夠用了。
前面通過(guò)一條簡(jiǎn)單的命令實(shí)現(xiàn)了自動(dòng)化的 versionCode,現(xiàn)在我們看怎么自動(dòng)化versionName。
在正常的發(fā)布流程中,在發(fā)布新版本的時(shí)候,都會(huì)在版本庫(kù)中打 tag。一般情況下,tag 名就是版本名,而且也建議這么做,因?yàn)槿绻硞€(gè)版本出現(xiàn) bug,也可以正好 checkout 這個(gè) tag 來(lái)查看代碼。所以,現(xiàn)在的問(wèn)題就是怎么自動(dòng)獲得 git 庫(kù)中新的新 tag?原來(lái),git 早就提供了命令 git describe,它的功能就是獲取從當(dāng)期 commit 到距離它近的 tag 的描述。默認(rèn)都是 annoted tag,如果要指所有的類(lèi)型的 tag 的話,就加 --tags參數(shù)。
此命令的詳細(xì)介紹在這里:git-describe。舉例一個(gè)簡(jiǎn)單的例子,假如你的當(dāng)前代碼狀態(tài)如下:
--A--B-...-C-->
| |
v1.0 v1.1
執(zhí)行 git describe 的結(jié)果是:v1.1,如果是如下的情況:
--A--B-...-C--D-->
| |
v1.0 v1.1
執(zhí)行 git describe 的結(jié)果是:v1.1-1-gXXXXXX,其中 1 表示當(dāng)前代碼距離近的 tag v1.1 一個(gè) commit,新的 commit 的 id 是 XXXXXX。
可見(jiàn),describe 命令很好的描述了當(dāng)前的分支的版本狀態(tài),我們可以直接使用這個(gè)它的輸出作為版本號(hào)。在 build.gradle 中的使用如下:
def cmd = 'git describe --tags'
def version = cmd.execute().text.trim()
android {
defaultConfig {
versionName version
}
}
這樣就可以自動(dòng)抽取 git 中的 tag 為版本名了。有些同學(xué)可能接受不了這樣版本名字 v1.1-1-gXXXXXX,這里也可以稍微做一些修改,使版本號(hào)更好看,如下:
def pattern = "-(\\d+)-g"
def matcher = version =~ pattern
if (matcher) {
version = version.substring(0, matcher.start()) + "." + matcher[0][1]
} else {
version = version + ".0"
}
這樣的話,上面的版本名就變?yōu)榱?nbsp;v1.0.0 和 v1.1.1 了。
前面的那篇文章中說(shuō)了,為了盡可能減少 gradle 腳本的運(yùn)算,提高開(kāi)發(fā)速度,我們可以把這樣的自動(dòng)版本的計(jì)算放到 release 編譯中去。后的寫(xiě)法如下:
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()
}
}
}
至此,結(jié)合 git 和 gradle 我們就實(shí)現(xiàn)了自動(dòng)版本號(hào)。
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個(gè)人觀點(diǎn), 并不代表本站贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé),本站只提供參考并不構(gòu)成任何投資及應(yīng)用建議。本站是一個(gè)個(gè)人學(xué)習(xí)交流的平臺(tái),網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對(duì)作者和來(lái)源進(jìn)行了通告,但是能力有限或疏忽,造成漏登,請(qǐng)及時(shí)聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對(duì)此聲明的最終解釋權(quán)。