[iOS-Release] 自動修改構建號

Version 和 Build 的概念

在應用 target 的 General 面板中有兩個設置項,分別為 Version 和 Build,它們實際對應了 Info.plist 文件中的兩項:

  • Bundle versions string, short(CFBundleShortVersionString)
  • Bundle version(CFBundleVersion)

這兩項都是用來標識應用的版本號。區別在于,Version 標識應用程序的發布版本號,格式應采用語義化的版本號,而 Build 則用來標識產品構建時的內部版本號(包括發布與未發布的),簡單的可使用遞增的整數表示。Version 是對外向用戶顯示說明的,而 Build 是開發內部用來唯一確定一次分發版本的。這里是官方介紹:Setting the Version Number and Build String

Version 一般在應用發布或更新時由產品部門確定,在了解清楚兩者的不同后,我們主要關注開發中使用的構建號。Build 可以方便我們清晰的追蹤構建的版本,比如在發布前,隨著測試與修復 bug 的進行,我們需要不斷的給測試人員提供新的版本,這時,通過構建版本號就可以清晰的標識具體的測試版本。或者我們可以通過構建版本號來區分收集的 Crash 信息。

構建版本號的自動修改

通過上述對 Build 的介紹我們知道,構建版本號是隨著內部分發版本而需要不斷更新的。為了提高效率,我們可以讓構建版本號在產品構建過程中自動更新,方法是在應用 target 的 Build Phases 面板中添加用于更改構建版本號的自定義腳本。

需要將 Run Script 步驟拖放到 Copy Bundle Resources 步驟之前,這樣可以保證 CFBundleVersion 的值與最新一次的構建版本一致,否則 CFBundleVersion 的值為下一次的構建版本。

修改構建版本號的腳本

通過 shell 腳本,我們可以實現不同格式的構建版本號的自動修改。

遞增整數

最簡單的構建版本號的設置就是,隨著每一次的構建,整數版本號遞增1。第一種方式是使用蘋果公司提供的命令agvtool,這里是該命令的介紹:Automating Version and Build Numbers Using agvtool。在腳本中只需要簡單的執行以下命令:

agvtool next-version -all

另一種方式就是獲取當前的構建版本號,加1后再重新設置構建版本號:

build_number=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" ${INFOPLIST_FILE})
build_number=$((${build_number} + 1))
/usr/libexec/PlistBuddy -c "Set CFBundleVersion ${build_number}" ${INFOPLIST_FILE}

構建號與版本號的拼接:

build_number=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" ${INFOPLIST_FILE})
version_number=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" ${INFOPLIST_FILE})
build_number=$(echo $build_number|sed 's/.*\./''/')
build_number=$((${build_number} + 1))
/usr/libexec/PlistBuddy -c "Set CFBundleVersion ${version_number}.${build_number}" ${INFOPLIST_FILE}
基于 Git

我們也可以通過 Git 的提交信息來標識構建版本,如以提交次數作為構建版本:

build_number=$(git rev-list HEAD | wc -l | awk '{print $1}')
/usr/libexec/PlistBuddy -c "Set CFBundleVersion ${build_number}" ${INFOPLIST_FILE}

或者以最新提交的 ID 作為構建版本號:

build_number=$(git rev-parse --short HEAD)
/usr/libexec/PlistBuddy -c "Set CFBundleVersion ${build_number}" ${INFOPLIST_FILE}
基于日期時間

還可以用不同格式化的當前時間作為構建版本號

build_number=$(date +%Y%m%d)
/usr/libexec/PlistBuddy -c "Set CFBundleVersion ${build_number}" ${INFOPLIST_FILE}

自定義腳本

上述各種格式的腳本都可以進行修改以符合自己的格式需求,而且可以對各種格式信息進行組合。最終,我選擇的格式為日期+當天構建次數+環境標識,如:201701051R。這種格式相比單純的構建次數遞增,除了達到唯一確定標識一次構建版本的作用外,還提供了更有意義的信息,比如測試人員可以很容易的根據環境標識選擇要測試環境對應的構建版本。以下是我使用的腳本:

if [ ${CONFIGURATION} != "Develop" ]
then

last_build_version=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" ${INFOPLIST_FILE})
last_build_date=${last_build_version:0:8}
#因為最后一位為環境標識位,所以構建次數通過截取第九位到倒數第二位的字符確定。
last_build_number_length=$((${#last_build_version} - 9))
last_build_number=${last_build_version:8:$last_build_number_length}
current_date=$(date +%Y%m%d)

if [ ${last_build_date} = ${current_date} ]; then
    build_number=$(expr ${last_build_number} + 1)
else
    build_number="1"
fi

build_number=$(printf "%02d" ${build_number})

if [ ${CONFIGURATION} = "Debug" ]; then
    environment_flag="S"
elif [ ${CONFIGURATION} = "Release" ]; then
    environment_flag="P"
fi

build_version=${current_date}${build_number}${environment_flag}
/usr/libexec/PlistBuddy -c "Set CFBundleVersion ${build_version}" ${INFOPLIST_FILE}

fi

腳本中最外層有一個判斷,作用是過濾所有開發調試中的構建過程。只有真正構建一個要分發出去的產品時,才應計入構建版本號中。而另一種方式則是勾選 Run Script 面板中的 Run Script only when installing 選項,勾選該選項后,腳本在平常調試構建過程中并不會執行,而只在 Archive 的構建過程時才會執行,這樣也就不需要添加外層的判斷了。

對于腳本中使用到的一些環境變量,如 CONFIGURATION,INFOPLIST_FILE 等,如果你勾選了 Run Script 面板中的 Show environment variables in build log 選項,則可以在構建過程的 log 中看到所有添加的環境變量,主要是當前 Build Settings 中的值。

2019.7.11 對腳本的更新

  • 簡化變量名,在當前語境下,不需要寫 last,去掉后意義仍然明確。
  • 日期過長,去掉前兩位的世紀標識,采用六位標識,如 190711,在可預見的應用生命周期內,不會有歧義。
  • 根據文檔 CFBundleVersion 中的定義,構建號只允許由數字和.組成。通過字母標識服務器環境,在上傳應用商店時還需要手動修改構建號,所以改用數字標識。文檔中定義的格式及意義與版本號一致,所以不采用。
  • 連續的數字閱讀起來不方便,用.分割不同的意義塊。
  • Build Phases 中的默認腳本名 "Run Script" 可修改,設置為 "Update Build Version"。

最終確定的格式為:日期.當天的構建次數.服務器環境標識。

build_version=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" ${INFOPLIST_FILE})
# 數組用括號來表示,元素用"空格"符號分割開。所以操作字符串將點換成空格,使其中每一段可直接轉換為數組元素。
array=(${build_version//./ })
build_date=${array[0]}
build_number=${array[1]}
current_date=$(date +%y%m%d)

if [ ${build_date} = ${current_date} ]; then
build_number=$((${build_number} + 1))
else
build_number=1
fi

if [ ${CONFIGURATION} = "Debug" ]; then
environment_flag=0
elif [ ${CONFIGURATION} = "Release" ]; then
environment_flag=1
fi

build_version=${current_date}.${build_number}.${environment_flag}
/usr/libexec/PlistBuddy -c "Set CFBundleVersion ${build_version}" ${INFOPLIST_FILE}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Write In Frist:在這嚴肅??的提出一個問題,希望有幸被大牛看到解釋指導。Q:在使用腳本更新build號...
    Leehf閱讀 5,451評論 5 9
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,925評論 6 342
  • 我前面寫了一篇關于抑郁的文章,被很多陌生的朋友接納和認可,還有不斷跟我訴說、暢談的,我不知道,這個世界怎么了。讀者...
    何語婳閱讀 690評論 16 7
  • 夜已深,難入眠。人生如旅行,過程是享受,終點是向往。
    進取A閱讀 144評論 0 0