[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}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • Write In Frist:在这严肃😠的提出一个问题,希望有幸被大牛看到解释指导。Q:在使用脚本更新build号...
    Leehf阅读 5,365评论 5 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,803评论 6 342
  • 我前面写了一篇关于抑郁的文章,被很多陌生的朋友接纳和认可,还有不断跟我诉说、畅谈的,我不知道,这个世界怎么了。读者...
    何语婳阅读 664评论 16 7
  • 夜已深,难入眠。人生如旅行,过程是享受,终点是向往。
    进取A阅读 140评论 0 0