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中文站投稿或者參與內容翻譯工作,請郵件至[email protected]。也歡迎大家通過新浪微博(@InfoQ)或者騰訊微博(@InfoQ)關注我們,並與我們的編輯和其他讀者朋友交流。
http://www.infoq.com/cn/articles/build-ios-continuous-integration-platform-part1?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_articles_clk