您的位置:首页 > 移动开发 > IOS开发

构建iOS持续集成平台(一)——自动化构建和依赖管理

2015-06-02 18:34 573 查看
  2000年Matin Fowler发表文章Continuous Integration【1】;2007年,Paul Duvall, Steve Matyas和 Andrew Glover合著的《Continuous Integration:Improving Software Quality and Reducing Risk》 【2】出版发行,该书获得了2008年的图灵大奖。持续集成理念经过10多年的发展,已经成为了业界的标准。在Java, Ruby的世界已经诞生了非常成熟的持续集成工具和实践,而对于iOS领域来说,因为技术本身相对比较年轻和苹果与生俱来的封闭思想,在持续集成方面的发展相对滞后一些,但是,随着越来越多的iOS开发者的涌入,以及各个互联网巨头加大对iOS开发的投入,诞生了一大批非常好用的持续集成工具和服务,本文的目的就是介绍一下如何有效的利用这些类库,服务快速构建一个iOS开发环境下的持续集成平台。


自动化构建

  在MartinFowler的文章[1]中关于自动化的构建定义如下:
Anyone should be able to bring in a virgin machine, check the sources
out of the repository, issue a single command, and have a running
system on their machine.


  因此,自动化构建的的首要前提是有一个支持自动化构建的命令行工具,可以让开发人员可以通过一个简单的命令运行当前项目。


命令行工具

  自动化构建的命令行工具比持续集成的概念要诞生得早很多,几十年前,Unix世界就已经有了Make,而Java世界有Ant,Maven,以及当前最流行的Gradle,.Net世界则有Nant和MSBuild。作为以GUI和命令行操作结合的完美性著称的苹果公司来说,当然也不会忘记为自己的封闭的iOS系统提供开发环境下命令行编译工具:xcodebuild【3】


xcodebuild

  在介绍xcodebuild之前,需要先弄清楚一些在XCode环境下的一些概念【4】:

Workspace:简单来说,Workspace就是一个容器,在该容器中可以存放多个你创建的Xcode Project, 以及其他的项目中需要使用到的文件。使用Workspace的好处有,1),扩展项目的可视域,即可以在多个项目之间跳转,重构,一个项目可以使用另一个项目的输出。Workspace会负责各个Project之间提供各种相互依赖的关系;2),多个项目之间共享Build目录。
Project:指一个项目,该项目会负责管理生成一个或者多个软件产品的全部文件和配置,一个Project可以包含多个Target。
Target:一个Target是指在一个Project中构建的一个产品,它包含了构建该产品的所有文件,以及如何构建该产品的配置。
Scheme:一个定义好构建过程的Target成为一个Scheme。可在Scheme中定义的Target的构建过程有:Build/Run/Test/Profile/Analyze/Archive
BuildSetting:配置产品的Build设置,比方说,使用哪个Architectures?使用哪个版本的SDK?。在Xcode Project中,有Project级别的Build Setting,也有Target级别的Build Setting。Build一个产品时一定是针对某个Target的,因此,XCode中总是优先选择Target的Build Setting,如果Target没有配置,则会使用Project的Build
Setting。

  弄清楚上面的这些概念之后,xcodebuild就很好理解了,官网上对其作用的描述如下:
xcodebuild builds one or more targets contained in an Xcode
project, or builds a scheme contained in an Xcode workspace or
Xcode project.


  xcodebuild就是用了构建产品的命令行工具,其用法可以归结为3个部分:

可构建的对象
构建行为
一些其他的辅助命令

  可以构建的对象有,默认情况下会运行project下的第一个target:

workspace:必须和“-scheme”一起使用,构建该workspace下的一个scheme。
project:当根目录下有多个Project的时候,必须使用“-project”指定project,然后会运行
target:构建某个Target
scheme:和“-workspace”一起使用,指定构建的scheme。
……

  构建行为包括:

clean:清除build目录下的
build: 构建
test: 测试某个scheme,必须和"-scheme"一起使用
archive:打包,必须和“-scheme”一起使用
……

  辅助命令包括:

-sdk:指定构建使用的SDK
-list:列出当前项目下所有的Target和scheme。
-version:版本信息
…...

  关于xcodebuild更多详细的命令行请参见:https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html

  下图是使用XcodeBuild运行一个scheme的build的结果:

  


  了解了xcodebuild的用法之后,接下来分析一下xcodebuild的主要缺陷:

从上图直接可以得到的感觉,其脚本输出的可读性极差,
只能要么完整的运行一个target或者scheme,要么全部不运行。不能指定运行Target中特定的测试。
最令人发指的是,XCode 4中的xcodebuild居然不支持iOSUnitTest的Target【5】,当我尝试运行一个iOS App的测试target时,得到如下的错误:

  


  对于上面提到的缺陷,Facebook给出了他们的解决方案:xctool【6】


xctool

  xctool在 其主页直接表明了其目的:
xctool is a replacement for Apple's xcodebuild that makes it easier  to build and
test iOS and Mac products. It's especially helpful for continuous integration.


  其作用是替代xcodebuild,目的是让构建和测试更加容易,更好的支持持续集成。从个人感受来看,它的确成功取代了xcodebuild。但是xctool说到底只是对xcodebuild的一个封装,只是提供了更加丰富的build指令,因此,使用xctool的前提是xcodebuild已经存在,且能正常工作。


安装

  xctool的安装非常简单,只需要clone xctool的repository到项目根目录就可以使用, 如果你的机器上安装有Homebrew,可以通过“brew install xctool”命令直接安装。(注意:使用xctool前一定要首先确认xcodebuild已安装且能正确工作)。


用法

  关于xctool的用法就更加人性化了,几乎可以重用所有的xcodebuild的指令,配置。只需要注意一下几点:

xctool不支持target构建,只能使用scheme构建。
支持“-only”指令运行指定的测试。
支持多种格式的build报告。

  例子:
path/to/xctool.sh
-workspaceYourWorkspace.xcworkspace
-schemeYourScheme
test -only SomeTestTarget:SomeTestClass/testSomeMethod


  下图是我使用xctool运行test的效果:

  



常见问题:

  No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=armv7 armv7s).

  解决方法:到Project Setting中,把"Build Active Architecture Only"设置为NO

  Code Sign error: A valid provisioning profile matching the application's Identifier 'dk.muncken.MyApp' could not be found

  解决方法:通过“-sdkiphonesimulator”指定SDK,从而能够使用符合iOS约定的application Identifier。


依赖管理

  选定了命令行工具之后, 接下来可以考虑下依赖管理的问题了。我到现在还记得几年前,刚从Ant转到使用Maven的那种爽快的感觉。后来,进入Ruby的世界,其与生俱来的Gem管理系统,也让其依赖管理变得极其简单。 对于iOS平台来说,在做项目时,经常需要使用到各种各样的第三方Framework,这同样需要一个爽快的依赖管理系统,不然的话,各位可以想象一下重复的下载Framework文件,拖入各个Target的Build Phase的Link Binary With Libraries中的场景。这种重复的劳动对于“懒惰”的程序员来说,是很难接受的,于是,活跃的社区开发者们提供了这样的一个工具:Cocoapods【7】

  Cocoapods开始于2011年8月12日,经过2年多的发展,现在已经超过2500次提交,并且持续保持活跃更新,目前已成为iOS领域最流行的第三方依赖管理工具。从技术层面来说,其是一个Ruby Gem,从功能层面来说,其是一个iOS平台下的依赖管理工具,为iOS项目开发提供了类似于在Ruby世界使用Gem的依赖管理体验。


安装

  前面提到cocoapods本质上是一个Ruby Gem,因此,其使用前提首先是Ruby开发环境。庆幸的是,Mac下都自带Ruby。这样,只需要简单的2条命令,就可以把cocoapods安装好:
$ [sudo] gem install cocoapods
$ pod setup


用法

  cocoapods的使用方式和使用Ruby Gem非常相似,首先需要在项目根目录下创建文件Podfile,在Podfile中,开发人员只需要按照规则配置好如下内容就好:

项目支持的平台,版本(iOS/OSX)
每个target的第三方依赖

  例子:
platform :ios, '6.0'
inhibit_all_warnings!
xcodeproj `MyProject`
pod 'ObjectiveSugar', '~> 0.5'
target :test do
pod 'OCMock', '~> 2.0.1'
end
post_install do |installer|
installer.project.targets.each do |target|
puts "#{target.name}"
end
end


  修改好配置文件之后,只需要简单的使用“pod install”即可安装好所有的依赖,执行该命令之后,在项目跟目录下会出现“.xcworkspace”和“Pods”两个目录:

  


  接下来,开发者需要使用xcworkspace打开项目而不是使用xcodeproject,打开项目之后,在项目目录下除了自己的project以外,还可以看到一个叫做Pods的项目,该项目会为每一个依赖创建一个target:

  


  


  在Podfile中,还可以指定依赖专属于某个Target,
target :CocoaPodsTest do
pod 'OCMock', '~> 2.0.1'
pod 'OCHamcrest'
end


  如果你记不清楚某个依赖库的名称,可以使用“pod search <name>”模糊搜索依赖库中的相似库,另外,如果你想使用的库在cocoapods的中央库中找不到,那么,你可以考虑为开源社区做做贡献,把你觉得好用的库添加到中央库中,Cocoapods的官网上有具体的步骤【8】


原理

  CocoaPods的原理思想基本上来自于Jonah Williams的博客“Using Open Source Static Libraries in Xcode 4”【9】,当使用“pod install”安装文件时,cocoapods做了如下这些事:

创建或者更新当前的workspace
创建一个新的项目来存放静态库
把静态库会编译生成的libpods.a文件配置到target的build phase的link with libraries中
在依赖项目中创建*.xcconfig文件,指定在编译时的一些参数和依赖
添加一个新的名为“Copy Pods Resource”的Build Phase,该build phase会使用"${SRCROOT}/Pods/Pods-CocoaPodsTest-resources.sh"把Pods下的资源文件拷贝到app bundle下。


注意事项

  当使用xctool作为命令行工具构建项目时,使用cocoapods管理依赖时,需要做一些额外的配置:

编辑Scheme,把pods静态库项目作为显式的依赖添加到项目的build中,
把pods依赖项目拖动到本来的项目之上,表示先编译pods静态库项目,再编译自己的项目。

  


  感谢张凯峰对本文的审校。

  给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。

来自infoq
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: