objc系列译文(6.5):为iOS项目搭建Travis CI服务器

382 查看

你是否曾经试着为你的iOS项目搭建一台支持持续集成的服务器,从我的个人经验而言,这可不是一个轻松的活。你需要准备一部Mac,安装好全部所需的软件和插件。你要负责管理所有的用户账户并提供安全保护。

原本你想节省的时间,最终你会发现你花费了大量的时间去维护这台服务器。不过如果你的项目托管在GitHub上,现在有了新的希望:Travis CI。该服务可以为你的项目提供持续集成的支持,也就意味着它会负责好托管一个项目的所有细节。在Ruby的世界中,Travis CI已久负盛名。从2013年4月开始,Travis也开始支持iOS和Mac平台。

在这篇文章中,我会向你展示如何一步步为你的项目集成Travis。不仅包括编译项目和进行单元测试,还能够将你的应用投送到你所有的测试设备上。为了演示,我在GitHub上放了一个示例项目。在这篇文章的最后,我会教你如何用Travis去定位程序中的错误。

GitHub集成

我最喜欢Travis的一点就是他与GitHub的Web UI集成的非常好。譬如pull请求。Travis会为每次请求都执行编译操作。如果一切正常,pull请求在GitHub上看起来就像这样:

万一编译不成功,GitHub页面会相应的改变颜色给予提醒:

链接Travis和GitHub

让我们看一下如何链接你的GitHub项目到Travis。使用你的GitHub账号登陆Travis。对于私有工作目录,你需要注册一个Travis专业版账号。

登陆成功后,你就可以为你的项目打开Travis支持。找到属性页面,在此列出了你的所有GitHub项目。不过要注意,如果你此后创建了一个新的工作目录,要使用Sync now按钮进行同步。Travis只会偶尔更新你的项目列表。

现在只需要打开这个开关就可以为你的项目添加Travis服务。以后你会看到Travis会和你的GitHub项目设置相关联。下一步应该告诉Travis当它收到项目改动之后该做什么。

轻量级的项目配置

Travis CI需要你的项目的一些基本信息。在你项目的根目录创建一个名叫.travis.yml的文件,内容如下:

Travis编译器运行在虚拟机环境下.已经使用Ruby,Homebrew,CocoaPods和一些编译脚本进行过配置。上述的配置项已经足够编译你的项目了。

预装的编译脚本会分析你的Xcode项目,编译项目下的所有Target。如果所有文件都没有编译错误测试也没有跳出项目就编译成功了。现在可以将你的改动Push到GitHub看看能成功编译。

虽然这看起来好像很简单,不过对你的项目不一定适用。几乎没有什么文档来指导用户如何配置默认的编译行为。举个栗子, 有一次我没有用模拟器的SDK导致检查应用签名时发生了错误。如果刚刚那个最轻量级的配置对你的项目不适用的话,让我们来看一下如何用定制的编译命令来适用Travis。

定义编译命令

Travis使用命令行来编译你的项目。因此,第一步就是使项目能够在本地编译。作为Xcode命令行工具的一部分,Apple提供了xcodebuild命令。

打开你的终端输入:

这会列出xcodebuild可用的所有参数。如果命令执行不成功,确保你的命令行工具已经成功安装。通常一个常见的编译命令看起来像这样:

使用iphonesimulator SDK是为了避免应用签名错误。这是必须的一步直到我们稍后引入证书为止。通过设置ONLY_ACTIVE_ARCH=NO我们可以确保在模拟器的架构下编译。你也可以设置额外的属性。用man xcodebuild来阅读文档。

对于使用CocoaPods的项目,你需要指定workspace和scheme。

Schemes是由Xcode自动生成的,但这在服务器上不会发生。确保所有的scheme都被设为shared并加入到工作目录中。否则它只会在本地工作而不会被Travis CI识别。

我们的示例项目下的.travis.yml文件现在应该看起来像这样:

运行测试

通常对于测试来说你会使用如下的命令(注意test属性)

xcodebuild test -workspace {workspace}.xcworkspace -scheme {test_scheme} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO

不幸的是xcodebuild并不能支持多target以及iOS的应用测试。苹果已经在着手解决这个问题,不过我建议使用Xctool来代替。

Xctool

Xctool是来自Facebook的命令行工具,他可以帮助你更加轻松快捷的编译测试你的应用。他的彩色输出信息比xcodebuild更加简洁直观,结构清晰。同时还添加了对逻辑测试,应用测试的支持。

Travis中已经预装了xctool。要在本地测试的话,需要用Homebrew先安装xctool:

用法非常简单,xctool 使用跟 xcodebuild相同的参数:

xctool test -workspace TravisExample.xcworkspace -scheme TravisExampleTests -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO

这要这些命令在本地能正常工作,我们就可以把他们添加到.travis.yml文件里:

language: objective-c

script:

  – xctool -workspace TravisExample.xcworkspace -scheme TravisExample -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO

  – xctool test -workspace TravisExample.xcworkspace -scheme TravisExampleTests -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO

目前我们所添加的配置已经足够编译一个框架类的应用。我们能够保证项目可以正常编译并通过测试。但对于真正的iOS应用来说,我们希望在真实的物理设备上进行测试。很显然,我们要借助Travis来帮我们自动部署。整个过程的第一步,我们需要给我们的应用签名。

应用签名

为了在Travis中给我们的应用签名,我们需要准备好所有必要的证书和配置文件。就像每个iOS开发人员知道的那样,这可能是最困难的一步。后面我们将写一些脚本来帮助我们在服务器上给应用签名。

证书和配置文件

  1. 苹果全球开发者关系认证

从苹果的配置页面中下载或者从你的Keychain中导出,将它保存到你的项目目录下scripts/certs/apple.cer这个位置。

2.  iPhone发布证书 + 私钥

如果你还没有一个iPhone发布证书你需要创建一个。登陆你的苹果开发者账号,你可以跟随下面的步骤创建一个生产环境的新证书(Certificates > Production > Add > App Store and Ad Hoc)。确保你已经下载并安装了这个证书。以后你可以在你的Keychain中找到它,还有一个捆绑的私钥。现在打开你Mac上的Keychain应用:

右击证书选择导出将其放在scripts/certs/dist.cer路径,在导出捆绑的私钥,保存到scripts/certs/dist.p12。可以根据你的需要设置一个密码。

Travis需要知道你的私钥密码,我们需要将其储存在某个地方。显然我们不想用简单的文本来存储这个密码。我们可以利用Travis的安全环境变量。打开终端进入包含.travis.yml文件的目录。首先用gem install travis命令安装Travis gem。安装完成后你就可以用以下命令添加密码:

travis encrypt “KEY_PASSWORD={password}” –add

这样就可以安装一个叫做KEY_PASSWORD的加密环境变量到你的.travis.yml配置文件。在任何可以被Travis CI执行的脚本中都可以使用这个变量。

3. iOS 移动设备备案文件(发布用)

如果你还没有一个发布用的移动设备备案文件。根据你的开发者账号类型,你可以选择Ad Hoc或者In House两种不同的备案文件(Provisioning Profiles > Distribution > Add > Ad Hoc or In House).下载将其保存到scripts/profile/目录下。

我们需要在Travis中访问此备案文件,所以我们需要将此文件的名字存储为一个全局变量。譬如我们可以将其命名为TravisExample_Ad_Hoc.mobileprovision,像这样添加:

这里还有两个声明的全局变量。APP_NAME通常指的就是你的项目主target的名字。DEVELOPER_NAME里是你在项目主target下Xcode Build Settings 中Code Signing Identity > Release里面看到的名字。最后搜索一下你应用的Ad Hoc或者In House配置文件,将其中的黑体文字全部去掉。根据你设置的不同,在一些属性的方括号里面可能不会有任何信息。

加密证书和备案文件

不过你的GitHub权限是公开的。你可能会想要给你的证书和备案文件加密,因为他们包含了你应用的重要信息。如果你使用的是一个私有目录,你可以跳过这一小节。

首先我们需要想出一个密码来加密我们所有的文件。在下面的例子中,我们使用foo这个单词,你完全可以将其替换为使用于你项目的更安全的密码。在命令行中需要使用openssl来加密这些敏感文件: