iOS开发必备 - 搭建自动化构建服务

本篇文章讲述了如何使用Jenkins搭建iOS的自动化构建环境。

iOS自动化构建官方有篇文章介绍Xcode持续集成, 是基于Xcode Server以及Xcode Bots去实现, 但是系统依赖和版本依赖过于严重, 并且需要在Xcode中配置Target的Shared属性, 耦合性太强, 因此不建议使用。

为什么客户端需要自动化构建

个人觉得最主要的原因是需要提高编码效率, 其次是方便测试与集成

  1. <font size=4>场景: 开发过程中, 不断的有产品或者测试介入, 需要你不定时的打包给他们提供体验与测试。</font>
    对于小工程来说, build一下可能就是几秒钟的事情, 但是对于大工程来说, 一次打包可能耗费5分钟乃至10分钟的开发时间。开发者一天中的有效开发时间是有限的, 在不断被打断的情况下, 开发者的产能实际上十分低效的。

  2. <font size=4>场景: 联调过程中, 需要有第三方的SDK接入联调, 需要不断的为对方更改SDK, 然后重新编译打包。</font>
    这种场景一般发生在多个公司协作的时候, 本人在开发某二手车批发软件的时候, 就曾遇到与第三方支付平台接入联调的问题, 一天中80%时间为对方提供打包服务, 生产效能过低。

  3. <font size=4>场景: 用户预览&客户演示。</font>
    这个场景比较类似第一个场景, 不过是面向不专业的人事或者客户, 需要不定时更新版本然后提供企业证书打包的预览版给老板和客户。严格意义上来说, 与第一个场景是同样一个场景。

  4. <font size=4>场景: 测试集成。</font>
    自动化构建和持续集成本来就是一码事, 如果你是个喜欢写集成测试的开发者, 那么在每一次打包编译的时候都要运行一次集成测试是很浪费时间的(PS: 集成测试不通过这个场景除外哦`)。将测试集成在构建步骤里面, 可以让自动化集成的所有行为在另外一台机器上工作, 工程师该干嘛还是干嘛去。

还有其他很多应用场景, 不过我个人暂时为了上述目的而搭建CI环境。最主要的目的是解放打包时间, 防止开发工作被打断。

准备工作

硬件环境

  1. <font size=4>搭载Macintosh系统的一台硬件设备或虚拟机。</font>
    既然是编译iOS应用, 那自然少不了苹果一系列的机器啦, 一台搭载Macintosh OS操作系统的电脑还是必须的, 目前本人采用的硬件方案是Mac mini。
    需要Macintosh是因为Xcode运行环境在该系统上, 因此如果你想利用脚本编译iOS应用, 你就需要Xcode, 如果你需要Xcode, 那你又必须处于Macintosh OS环境(哎~ 苹果的生态链)。
    鉴于目前国内的云服务器均为windows或者Linux, 您如果想用Geek的方式去搭建iOS的自动化构建方式, 可以尝试在云服务器上安装虚拟机然后运行Mac OS环境的方案。
  2. 在准备做CI的机器上安装Java SDK环境 & Xcode。
    Xcode可以用过App Store直接安装, Xcode体积非常大, 但是因为iOS编译脚本xcodebuile命令依赖于Xcode,因此Xcode是必须安装的。
    Java运行环境是Jenkins需要, 因为Jenkins是基于Java实现的一套构建系统, Java SDK可以通过Oracle的官网去下载最新的适用版本, 在本文书写的时候, 最新的Java SDK是JDK8, 下载地址为 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

安装Jenkins

  1. 在Mac OS环境下, 建议采用Homebrew来安装, 获取Homebrew建议采用官网的方式。通过Homebrew官网获取homebrew后执行如下命令:
$ brew install jenkins
  1. 利用homebrew安装完毕后, 可以在终端执行which jenkins查看是否已经安装成功。
  2. 在终端执行jenkins命令启动Jenkins(PS: 默认占用8080端口会导致启动失败), 此处有可能会出现Jenkins ssl证书过期的问题, 可以通过修改os系统时间, 调整为ssl支持的时间来解决, 否则安装Jenkins插件可能会失败。(jenkins命令依赖Java开发环境, 旧版本的Jenkins需要自己去配置bash alias)
  3. 打开浏览器, 访问http://localhost:8080, 查看Jenkins是否正常启动(默认端口8080)。

配置工作

Jenkins插件配置

Jenkins项目

Jenkins是个生态比较完善的自动化构建系统, 提供了各种的可扩展插件给用户下载, 同时又开放接口, 让大家自主开发对应的插件。插件管理路径是系统管理->管理插件

插件索引默认并不是最新的, 需要大家手动更新, 在管理插件->可选插件的右下角有个立即获取按钮, 点击即可获取最新的插件索引。

PS: <font color='red'>有时候官方索引的地址ssl证书过期导致索引会更新失败, 大家可以通过浏览器调试获取证书到期时间, 然后将本机时间调整为过期以前的时间即可解决该问题。</font>(apache有时候也不靠谱啊。。)

每个开发者根据不同的业务场景需要用到不同的插件, 本文就不在这里赘述, 大家自由发挥吧。

Jenkins账户权限配置

Jenkins用户权限配置和本文主题无关, 主要是方便大家对Jenkins用户进行访问控制。可以参考文章"Jenkins安全配置/访问控制/审计"或文章"Jenkins使用经验谈5(用户的登录与权限设定等)"进行配置。

我个人是比较喜欢采用安全域里的Jenkins专有用户数据库进行配置, 因为自带的比较方便, 而且在不复杂的企业环境里面已经够用, 负责的企业环境就另当别论了。大致流程如下:

  1. 在Jenkins页面上注册一个新用户(当然可以导入)
  2. 系统管理->Configure Global Security里的授权策略进行定向配置, 个人偏好采用项目矩阵授权策略进行管理。

项目&脚本配置

本文重点是如何自动化编译iOS项目, 这个其实大家应该很熟悉了, 就是利用xcodebuild命令和xcrun组合进行脚本编译和签名。编译脚本的编写本质上不缺分环境(Jenkins服务器环境or本机环境), 因此我们需要确保本机环境的脚本能够正常的工作, 个人偏好使用bash环境(因为不用安装其它的依赖), 然后使用下述的模板进行填空。

#!/bin/bash
projAbbr='iOS_Bash_Build_Demo'

function autoBuild()
{
    prepareBuildEnv
    updatePodsDeps
    clearProjs
    buildProjs
    signProjs
    uploadAppFile
    echo ${projAbbr} '- ALL Action Completed!'
}

function prepareBuildEnv()
{
    # TODO - 执行编译器准备工作, 可以调整项目配置等执行任务
    # eg: mkdir xxx
}

function updatePodsDeps()
{
    # TODO - 更新Pod依赖
    # eg: pod install 
}

function clearProjs()
{
    # TODO - clean项目
    # eg: xcodebuild -workspace "demo.xcworkspace"  -scheme "targetName"  -configuration 'Release Adhoc' clean
}

function buildProjs()
{
    # TODO - 编译项目, 生产带证书签名的App文件
    # eg: xcodebuild -workspace "demo.xcworkspace" -sdk iphoneos -scheme "targetName" -configuration 'Release Adhoc' SYMROOT='$(PWD)'
    # eg: xcodebuild -workspace "demo.xcworkspace" -sdk iphoneos -scheme "targetName" -configuration 'Release Adhoc' CODE_SIGN_IDENTITY="keychain中证书代号名称" SYMROOT='$(PWD)'
}

function signProjs()
{
    # TODO - 填充签名脚本, 用于签名编译到的App, 打包成ipa文件
    # eg: xcrun -sdk iphoneos PackageApplication -v "demo.app" -o "demo.ipa" > $logPath
}

function uploadAppFile()
{
    # TODO - 上传App文件到发布平台
    # 蒲公英、Fir.im都是不错的选择哦
}

# 如果使用第三方平台, 一般不需要createPlist, 因为第三方平台都已经集成
function createPlist()
{
    # TODO - 创建Plist文件, 用于企业证书下载
}

autoBuild

上述脚本将编译步骤拆分为准备环境更新Cocoapodsclean项目build项目签名项目上传ipa文件六大步骤。脚本的每一个步骤其实都可以在Jenkins需找对应的插件进行图形化控制, 但是我本人喜欢编写脚本来轻量化Jenkins的依赖, 除非需要本地上传一些依赖配置的文件。

上述脚本的执行任务也可以通过组合CocoaPods Jenkins Integration插件、Xcode integration插件以及其他上传插件进行组合。但是我并不太喜欢过渡依赖Jenkins的图形界面, 因此并没有深度整合这两个插件。

<font style='bold' color='black'>脚本的核心代码注释在代码里的eg, xcodebuild命令进行clean以及build, 然后通过xcrun进行签名app生成ipa文件</font>

clean清理脚本示例:

xcodebuild -workspace "demo.xcworkspace"  -scheme "targetName"  -configuration 'Release Adhoc' clean

build编译脚本示例:

xcodebuild -workspace "demo.xcworkspace" -sdk iphoneos -scheme "targetName" -configuration 'Release Adhoc' CODE_SIGN_IDENTITY="keychain中证书代号名称" SYMROOT='$(PWD)

xcodebuild是Xcode Command Tool工具集里的一个命令, 可以通过-workspace指定固定的xcode工作空间或者通过-project指定固定的xcode项目。详细的参数可以参考官方文档

sign签名脚本示例:

xcrun -sdk iphoneos PackageApplication -v "demo.app" -o "demo.ipa"

xcrun命令可以将app文件打包成ipa文件, 主要依赖xcodebuild命令中指定的证书, 如果没有有效证书的话, 只能在越狱的环境中安装ipa。

大家可以尝试填充这个脚本, 来进行本地编译, 如果本地编译不通过, 那放在Jenkins上是肯定通过不了的。

具体的脚本内容每个人各不相同, Github上有个叫BashShell的项目里包含一个脚本示例build_install.sh, 该项目作者编写的脚本非常详细, 大家可以参考编写。

  • xcodebuild命令可以指定对应的签名文件, 可以通过预先上传签名文件到编译服务器的keychains中或者将证书存放于代码托管库中方便指定。
  • 通过Jenkins执行的脚本会默认注入一些全局环境变量, 例如${PWD}${CHANGES}等等。通过这些全局参数可以在执行脚本或者邮件等任务中打印动态数据。
  • Jenkins默认将返回值-1作为失败条件, 因此如果需要主动在脚本终止任务, return -1就可以触发Jenkins任务失败了。

好了, 准备工作已经差不多了, 可以先将自己的脚本本地测试下了哦~ 编译通过了就可以开始配置Jenkins任务啦~

开始自动化之旅

新建任务

编译脚本、编译环境都准备好, Jenkins也正常运行了, 接下来就是创建Jenkins任务了。

  1. 通过新建构建一个自由风格的软件项目。(同一个分支不同的任务也需要建立多个不同的Job, 每一个Job在服务器Home目录下的.jenkins文件夹下面会创建一个独立的job和workspace)

  2. 在配置界面配置对应的源码管理, 现在国内大部分开发者的开发项目应该依托于gitlab的吧。(gitlab需要制定对应的版本号)

  3. 设定自动执行循环时间: 在构建触发器勾选Poll SCM, 可以通过特定的表达式进行触发设定。点击输入框后方问号会提示触发表达式的规则与书写方式。

    • 例如12小时检查一次源码库更新可以表达如下:
    H H/12 * * *
    
    • 例如30分钟检查一次源码库更新可以表达如下:
    H/30 * * * *
    
  4. 构建栏点击增加构建步骤, 选择Execute Shell, 在Command栏里面执行预先保存的脚本文件。假如默认保存在项目根目录下的脚本文件名为jenkins.sh, 则输入如下代码:

    sh jenkins.sh
    
    • PS: 此处如果使用图形插件的同学们, 可以在这里添加对应的插件。
  5. 构建后任务可以添加邮件提醒以及上传FTP等执行动作。

自动发送邮件

  1. Jenkins默认提供了编译错误时候的自动邮件发送功能。 简易邮件功能需要在系统管理中的系统设置中的邮件通知栏进行设置。设置了邮件通知全局配置后, 在Jenkins Job配置的增加构建后步骤中可以配置简易的邮件通知, 简易版本的邮件通知仅仅支持在系统不稳定的时候通知相关的责任人与固定的邮件接收者。
  2. Email Extension Plugin: Jenkins一个很强大的邮件系统, 可以配置各种各样的邮件内容, 也可以定制不同的触发条件以及接受者。配置使用可以参考其他博文, 例如这篇《Jenkins中配置ESB构建后自动发邮件》

自动化测试

自动化测试可以参考构建脚本的使用方式, 单独书写shell任务去执行对应的测试任务, 也可以在构建脚本中提前穿插测试任务。本文中自动化测试并不是重点, 再这里不讨论, 后期更新相关内容。

自动上传

自动化的最后一步就是提供方便的下载地址给需要安装App的测试体验人员。需要一个平台提供一个方便苹果app下载的平台, 目前市面上以fir.im以及蒲公英使用率最广。

  1. 第三方平台: 以fir.im为例子, fir.im平台集成了ipa文件下载所需要plist文件以及一张优美的下载页。ipa文件第一次需要自己上传产生一个对应url地址。因为该平台本身依赖于七牛云存储, 因此使用该平台的上传脚本可以使用七牛的qrsync脚本实现, 具体怎么上传请参考fir.im的官方指南文档

  2. 自建平台: 自建平台比较麻烦, 需要产生对应的plist文件以及下载页面, 但是在很多高保密的企业下是不允许使用第三方平台的, 个人建议为公司搭建一个简易版本的fir.im, 方便以后使用。

  • 构建平台主要是承担的工作是企业证书下载环境的搭建以及历史版本的维护。企业证书下载环境最关键的部分是plist描述文件的生产以及https服务的支持(iOS7以后的items-service服务需要ssl且不接受伪造证书)
  • Bryce Zhange的博文里面有一篇教大家使用Apache和PHP搭建一个服务器的博文《iOS自动化编译》, 大家可以参考。该博文包含了如何使用Bruce(heyuan110)的编译脚本以及如何采用cat&EOF&>>去动态生成plist文件。

    PS: 个人不建议采用Apache搭建服务器, 可以试试Ngnix~ 其实最好是不要自己搭建了~

总结

本文主要是总结了我个人喜爱的方式, 使用Jenkins+Bash脚本在Mac OS X环境下搭建一个自动化构建环境。通过自动化构建环境来将自己从体验人员和测试人员不断要求安装包的麻烦中解放出来专心编写工程代码。Bash主要在于xcodebuildxcrun命令的使用, 以及提供了本人比较爱好的一套模板方便大家快速编写。Jenkins主要用于定时轮询代码和邮件通知。

文章的作用是给我本人备忘用的哈~ 水平有限, 有错误之处请大家及时指出哈~

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

推荐阅读更多精彩内容