更優雅的 Android 釋出自動版本號方案

發表於2016-03-03

以前看到一些自動化版本號打包的文章。如果您的專案是用 Git 管理的,並且恰巧又是使用 Gradle 編譯(應該絕大部分都是這樣的了吧?),本文試圖找到一種更加優雅的自動版本管理方法。

1 背景

我們都知道,Android 應用的版本管理是依賴 AndroidManifest.xml 中的兩個屬性:

  • android:versionCode:版本號,是一個大於 0 的整數,相當於 Build Number,隨著版本的更新,這個必須是遞增的。大的版本號,覆蓋更新小的版本號;
  • android:versionName:版本名,是一個字串,例如 "1.2.0",這個是給人看的版本名,系統並不關心這個值,但是合理的版本名,對後期的維護和 bug 修復也非常重要。

在使用了 Android Studio 或者 Gradle 編譯以後,我們通常是在 build.gradle 裡面定義這兩個值,如下:

2 自動版本號

在這篇文章中 6 tips to speed up your Gradle build 發現了,可以使用 Git 中 commit 的數量來作為版本號(versionCode)。方案如下:

這裡關鍵是這一行 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,所以完全夠用了。

3 自動版本名

前面通過一條簡單的命令實現了自動化的 versionCode,現在我們看怎麼自動化 versionName

在正常的釋出流程中,在釋出新版本的時候,都會在版本庫中打 tag。一般情況下,tag 名就是版本名,而且也建議這麼做,因為如果某個版本出現 bug,也可以正好 checkout 這個 tag 來檢視程式碼。所以,現在的問題就是怎麼自動獲得 git 庫中最新的最新 tag?原來,git 早就提供了命令 git describe,它的功能就是獲取從當期 commit 到距離它最近的 tag 的描述。預設都是 annoted tag,如果要指所有的型別的 tag 的話,就加 --tags 引數。

此命令的詳細介紹在這裡:git-describe。舉例一個簡單的例子,假如你的當前程式碼狀態如下:

執行 git describe 的結果是:v1.1,如果是如下的情況:

執行 git describe 的結果是:v1.1-1-gXXXXXX,其中 1 表示當前程式碼距離最近的 tag v1.1 一個 commit,最新的 commit 的 id 是 XXXXXX

可見,describe 命令很好的描述了當前的分支的版本狀態,我們可以直接使用這個它的輸出作為版本號。在 build.gradle 中的使用如下:

這樣就可以自動抽取 git 中的 tag 為版本名了。有些同學可能接受不了這樣版本名字 v1.1-1-gXXXXXX,這裡也可以稍微做一些修改,使版本號更好看,如下:

這樣的話,上面的版本名就變為了 v1.0.0v1.1.1 了。

4 優化

前面的那篇文章中說了,為了儘可能減少 gradle 指令碼的運算,提高開發速度,我們可以把這樣的自動版本的計算放到 release 編譯中去。最後的寫法如下:

至此,結合 git 和 gradle 我們就實現了自動版本號。

相關文章