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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容