Jenkins搭建iOS持續集成打包平臺

準備工作

Jenkins的安裝

Jenkins依賴于Java環境,首先需安裝和配置Java環境(PS:在下載的時候注意選擇JDK,而非JRE)

1.使用brew安裝:

brew install jenkins

如果報錯 brew: command not found,這是由于當前環境沒有安裝homebrew

安裝homebrew ,代碼執行:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安裝成功后,請重新安裝brew install jenkins

安裝成功后,瀏覽器會自動打開Jenkins網頁服務,如果沒有打開,請在瀏覽器輸入 http://localhost:8080/。如果不能打開 http://localhost:8080/ ,可能是Jenkins服務未開啟:

開啟Jenkins :

sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist

停用Jenkins :

sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist

如果報錯:/Library/LaunchDaemons/org.jenkins-ci.plist: No such file or directory

可以在命令行中開啟服務:

jenkins

此時Jenkins會在命令行里打印相關的運行日志,再在瀏覽器里輸入: http://localhost:8080/ 這種情況的話,如果關閉執行 jenkins命令的命令行窗口,Jenkins也會停止服務

Jenkins的配置

點擊系統管理->管理插件,在插件管理里面下載幾個比較有用的插件,當然可以根據自己的需求增減

1.插件的安裝

Xcode integration(用來配置打包參數的,需配置的參數和步驟較多,改用腳本打包)
Keychains and Provisioning Profiles Management(用來配置鑰匙串參數的,配合Xcode integration一同使用)
GitLab Plugin(用來關聯gitlab倉庫)
Gitlab Hook Plugin(用來配置hookurl,使gitlab在獲得push 等事件的時候能喚起Jenkins)
fir-plugin(用來上傳到fir的插件,易報錯,已改用腳本上傳)
Email Extension Plugin(用來在構建后發送郵件給測試的,smtp配置易出錯,已改用腳步發送)
Changelog Environment Plugin(用來獲取commits日志的,獲取插件請訪問 https://twiceyuan.com/2017/02/21/jenkins-changelog/)
BearyChat Plugin(用來在構建后發送通知給bearchat的,bearchat中選擇Jenkins機器人即可接受消息)

2.插件的使用

gitlab plugin

Markdown
  • 倉庫地址

  • 驗證方式(用戶名密碼或ssh)

  • 分支(想要構建的分支名稱,圖中傳了一個自定義的參數)

gitlab hook

Markdown
  • 在gitlab中設置-webhook中加入該URL,Jenkins即可在獲取push/merge事件后開始構建

changelog plugin

  • 勾選該選項后,即可獲取${SCM_CHANGELOG} commit日志參數,傳入腳步

bearchat plugin

  • 勾選該選項后,即可在構建完成后通知給bearchat中的Jenkins機器人

項目設置

在Jenkins中,構建項目以Job的形式存在,因此需要針對每個項目創建一個Job。有時候,一個項目中可能有多個分支同時在進行開發,為了分別進行構建,也可以針對每個分支創建一個Job。
創建Job的方式有多種,本次只需要創建Freestyle project類型的即可。
Main page -> New Item -> Freestyle project

對于一個持續集成打包平臺,每次打包都由4步組成:觸發構建、拉取代碼、執行構建、構建后處理。對應的,在每個Job中也對應了這幾項的配置。

1.Jenkins主頁,點擊左上角的新建按鈕開始新建一個Item

2.輸入Item的名稱,選擇構建一個自由風格的軟件項目

3.這里可以設置包的保留天數還有最大個數

4.配置參數化內容,如圖,可以用${name}在shell命令中取出對應的值

5.在源碼管理里面選擇git,然后配置git信息

要對項目進行構建,配置項目的代碼倉庫是必不可少的。由于當前我們的項目托管在Gitlab私有倉庫中,因此在此需要對Git進行配置。
【Source Code Management】配置欄目下,如果之前Gitlab plugin安裝成功,則會出現Git選項。

配置Git代碼倉庫時,有三項是必須配置的:倉庫URL地址(Repository URL)、倉庫權限校驗方式(Credentials),以及當前Job需要構建的代碼分支(Branches to build)。
在配置Repository URL時,選擇HTTPS URL或SSH URL均可。不過需要注意的是,Credentials要和Repository URL對應,也就是說:
如果Repository URL是HTTPS URL形式的,那么Credentials就要采用Gitlab用戶名密碼的校驗方式;如果Repository URL是SSH URL形式的,那么就需要先在Jenkins所在的服務器上創建一個SSH秘鑰對,并將公鑰添加到GitHub的SSH keys中,然后在填寫Credentials時,選擇SSH Username with private key的校驗方式,填入Gitlab Username、SSH私鑰、以及創建SSH秘鑰對時設置的Passphrase。

在配置Branches to build時,可以采用多種形式,包括分支名稱(branchName)、tagName、commitId等。其中分支名稱的形式用的最多,例如,若是構建master分支,則填寫master,若是構建develop分支,則填寫develop。
除了以上關于Git的必填配置項,有時根據項目的實際情況,可能還需要對Jenkins的默認配置項進行修改。比較常見的一種情況就是對clone的配置進行修改。

在Jenkins的默認配置中,clone代碼時會拉取所有歷史版本的代碼,而且默認的超時時限只有10分鐘。這就造成在某些項目中,由于代碼量本身就比較大,歷史版本也比較多,再加上網絡環境不是特別好,Jenkins根本沒法在10分鐘之內拉取完所有代碼,超時后任務就會被自動終止了(錯誤狀態碼143)。
這種問題的解決方式也很簡單,無非就是兩種思路,要么少拉取點代碼(不獲取歷史版本),要么提高超時時限。對應的配置在Advanced clone behaviours中:

Shallow clone:勾選后不獲取歷史版本;
Timeout (in minutes) for clone and fetch operation:配置后覆蓋默認的超時時限。

Markdown

6.配置構建觸發器

代碼倉庫配置好了,意味著Jenkins具有了訪問GitHub代碼倉庫的權限,可以成功地拉取代碼。

那Jenkins什么時候執行構建呢?

這就需要配置構建觸發策略,即構建觸發器,配置項位于【Build Triggers】欄目。

觸發器支持多種類型,常用的有:

  • 定期進行構建(Build periodically)
  • 根據提交進行構建(Build when a change is pushed to GitHub)
  • 定期檢測代碼更新,如有更新則進行構建(Poll SCM)

構建觸發器的選擇為復合選項,若選擇多種類型,則任一類型滿足構建條件時就會執行構建工作。如果所有類型都不選擇,則該Jenkins Job不執行自動構建,但可通過手動點擊【Build Now】觸發構建。

關于定時器(Schedule)的格式,簡述如下:

分鐘(0-59) 小時(0-23) 日期(1-31) 月(1-12) 周幾(0-7,0和7都是周日)


7.配置構建方式

常用的構建方式是根據構建對象的具體類型,安裝對應的插件,然后采用相應的構建方式。例如,若是構建iOS應用,安裝Xcode integration插件之后,就可以選擇Xcode,然后選擇Xcode進行構建。

該種方式的優勢是操作簡單,UI可視化,在場景不復雜的情況下可以快速滿足需求。不過缺點就是依賴于插件已有的功能,如果場景較復雜時可能單個插件還無法滿足需求,需要再安裝其它插件。而且,有些插件可能還存在一些問題,例如對某些操作系統版本或XCode版本兼容不佳,出現問題時我們就會比較被動。
我個人更傾向于另外一種方式,就是自己編寫打包腳本,在腳本中自定義實現所有的構建功能,然后在Execute Shell中執行。這種方式的靈活度更高,各種場景的構建需求都能滿足,出現問題后也能自行快速修復。

另外,對于iOS應用的構建,還有一個需要額外關注的點,就是開發者證書的配置。
如果是采用Xcode integration插件進行構建,配置會比較復雜,需要在Jenkins中導入開發證書,并填寫多個配置項。不過,如果是采用打包腳本進行構建的話,情況就會簡單許多。只要在Jenkins所運行的計算機中安裝好開發者證書,打包命令在Shell中能正常工作,那么在Jenkins中執行打包腳本也不會有什么問題。

8.至此,我們的Jenkins設置就全部完成了

點擊構建,就會開始構建項目了,構建一次,各個顏色代表的意義如下:


如果構建失敗了,可以去查看Console Output可以查看log日志:


關于iOS的構建

對iOS源碼進行構建,目標是要生成.ipa文件,即iOS應用安裝包。
當前,構建方式主要包括兩種:

xcodeuild:

  • 源碼 -> .archive文件 -> .ipa文件

xcrun:(xcode8后已被淘汰)

  • 源碼 -> .app文件 -> .ipa文件

這兩種方式的主要差異是生成的中間產物不同,對應的,兩種構建方式采用的命令也不同,我們只看xcodebuild這種.

源碼 -> .archive

# build archive file from source code
xcodebuild archive -workspace ${project_name}.xcworkspace \
                   -scheme ${scheme_name} \
                   -configuration ${build_configuration} \
                   -archivePath ${export_archive_path}

archive:對編譯結果進行歸檔,會生成一個.xcarchive的文件,位于-archivePath指定的目錄中。

需要注意的是,對模擬器類型的sdk無法使用archive命令.

.archive -> .ipa

# export ipa file from .archive
xcodebuild  -exportArchive \
            -archivePath ${export_archive_path} \
            -exportPath ${export_ipa_path} \
            -exportOptionsPlist ${ExportOptionsPlistPath}

參數說明

xcodebuild參數:

  • -workspace:需要打包的workspace,后面接的文件一定要是.xcworkspace結尾的;
  • -scheme:需要打包的Scheme,一般與${project_name}相同;
  • -configuration:需要打包的配置文件,我們一般在項目中添加多個配置,適合不同的環境,Release/Debug;
  • -archivePath:.xcarchive文件的路徑;
  • -exportPath:導出文件(.ipa)的路徑;
  • -exportOptionsPlist:根據configuration對應的plist文件;

補充說明

1、獲取Targets、Schemes、Configurations參數

在填寫target/workspace/scheme/configuration等參數時,如果不知道該怎么填寫,可以在項目根目錄下執行xcodebuild -list命令,它會列出當前項目的所有可選參數。

Information about project "Store":
    Targets:
        Store
        StoreCI
    Build Configurations:
        Debug
        Release
    If no build configuration is specified and -scheme is not passed then "Release" is used.
    Schemes:
        Store
        StoreCI

2.清除緩存文件

在每次build之后,工程目錄下會遺留一些緩存文件,以便下次build時減少編譯時間。然而,若因為工程配置錯誤等問題造成編譯失敗后,下次再編譯時就可能會受到緩存的影響。
因此,在持續集成構建腳本中,比較好的做法是在每次build之前都清理一下上一次編譯遺留的緩存文件。

xcodebuild clean -workspace ${project_name}.xcworkspace \
                 -scheme ${scheme_name} \
                 -configuration ${build_configuration}

3.處理Cocoapod依賴庫

若項目是采用Cocoapod管理項目依賴,每次拉取最新代碼后直接編譯可能會報錯。這往往是因為其他同事更新了依賴庫(新增了第三方庫或升級了某些庫),而本地還采用之前的第三方庫進行編譯,從而會出現依賴庫缺失或版本不匹配等問題。
應對的做法是,在每次build之前都更新一下Cocoapod。

# Update pod repository
pod repo update
# Install pod dependencies
pod install
# Install pod dependencies not update spec
pod install --verbose --no-repo-update

4.上傳FIR

fir publish ./xxx.ipa -T xxxxxx

5.提交AppStore(未完成)

/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool --validate-app -f ./xxx.ipa -u xxx -p xxx -t ios --output-format xml
/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool --upload-app -f ./xxx.ipa -u xxx -p xxx -t ios --output-format xml

6.發郵件

python sendEmail.py "日志" "用戶郵箱"

遇到的問題

Q1:Jenkins Xcode 證書設置錯誤 Code Sign error: No matching codesigning identity found: No codesigning identities

A1:Jenkins 集成Xcode 項目的時候在證書上遇到了問題。實際上如果在本地的話。只要Xcode工程里選擇了項目就不需要重新設置證書了。jenkins會自動找到這個證書,只要在build setting 里設置的是正常的。并且在xcode 里能正常編譯。

Check dependencies
Code Sign error: No codesigning identities found: No codesigning identities (i.e. certificate and private key pairs) that match the provisioning profile specified in your build settings (“qingyunDeveloper”) were found.

如果遇到類似的錯誤 解決辦法:
因為jenkins運行在Mac的守護進程模式,只是認為它是一個不同的用戶,所以不會有機會獲得鑰匙串或提供個人資料作為您登錄使用您的憑據,而我的證書是裝在“登錄”下的,這會導致代碼簽名有問題
解決辦法是首先打開keychain keys 找到apple 的開發者證書。然后復制。 再選擇左邊的系統(system)把剛復制的證書放進去。

如果這個還沒有解決。

接下來第二步:

找到你用戶下的Provisioning Profiles 文件。目錄為 /Users/xxx/Library/MobileDevice/Provisioning Profiles xxx表示你自己的用戶名
把這里面所有的證書復制到/Users/Shared/Jenkins/Library/MobileDevice/Provisioning Profile 這個文件。

參考資料:
http://code-dojo.blogspot.co.uk/2012/09/fix-ios-code-signing-issue-when-using.html

Q2:打包iOS有pod的項目,shell執行pod install時,提示pod command not found

A2:需要在shell第一行加上 #bin/bash -l 就行了,所以最終是這樣:

#!/bin/bash -l
export LANG=en_US.UTF-8
pod install --verbose --no-repo-update

Q3:有pod的項目提示schema找不到

A3:需要用xcode打開一次.xcworkspace就好了,或者在shell pod install之后下加上 open x.xcworkspace

Q4:jenkins 命令 command not found

A4:由于jenkins是用jenkins用戶啟動的,所以很多環境變量就沒有,導致很多命令起不來,所以需要把jenkins改為自己常用的用戶來啟動。默認jenkins的目錄是在/User/Share/Jenkins下的。這是安裝.pkg文件成功后自動創建了jenkins用戶,下面我們開始切換到常用用戶下。

1)我們先把jenkins停掉,執行:
sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist

然后刷新瀏覽器,發現jenkins頁面打不開了,說明成功停掉了

2)到Finder->application下找到jenkins/jenkins.war,雙擊啟動。然后刷新瀏覽器,發現又重新進入了jenkins的配置過程,正常配置完,返現jenkins根目錄變了,變成/User/當前用戶/.jenkins/

Q5:jenkins打包的時候需要鑰匙串密碼

A5:這個密碼是本地登陸密碼,如果不行,就得用jenkins用戶的密碼,直接重置jenkins密碼。在命令行執行
sudo passwd jenkins
可能要求先輸入當前用戶密碼,然后就提示Changing password for jenkins.設置新密碼就行了.

Q6:在使用jenkins打包時 出現xcodebuild: error: The workspace named "XXXX" does not contain a scheme named “XXX"

A6:首先在項目根目錄中使用 xcodebuild -list 獲得schema名稱
然后在該schema中勾選shared選項

Markdown

Q7:jenkins使用shell命令打IOS包報錯:user interaction is not allowed

A7:在編譯命令前加入以下命令:

security unlock-keychain -p "123456" ~/Library/Keychains/login.keychain

或者

echo "123456" | security unlock-keychain  ~/Library/Keychains/login.keychain

[要把鑰匙串解鎖,并配置訪問鑰匙串的密碼即可]

Q8:在自動化部署的時候,gitlab中的webhook無法訪問jenkins,報錯execution expired

A8:暫時沒找到辦法解決,可能是架設gitlab的局域網網段和jenkins的網段不一致

Q9:不能打包adHuc/appstore包的問題

A9:下載描述文件(需要把extension的描述文件一起下下來) p12文件一起安裝

Q10:在打包時出現多語言包損壞的問題

A10:不要用cocoapods的beta版

Q11:打包腳本報錯teamid不匹配

A11:Xcode近年來致力于自動管理開發證書,每個大版本都會有修改(有方便的地方也有坑的地方)。到了Xcode8,在target的General設置面板中直接新增了“Signing”,看得出來,Automatically manage signing選項是蘋果推薦的簽名方式。如果恰巧不幸,你的證書里的App ID與Xcode中的bundle ID不符,就應該關閉該選項,手動為某個configuration指定打包證書。不要忘記在腳本中-exportOptionsPlist指定的plist中配置對應的teamID。

總結

  • 自動打包是iOS開發中的一項基礎工作,作為自動化工作的一小部分往往被應用于CI系統。持續集成的內容很多,還有自動化測試、代碼靜態檢查、持續交付等內容。這篇文章是概括了其中一些方面,我們要做的還有很多。

接下來要做什么

  • OCLint -- 做為一個靜態代碼分析工具,我們引入 OCLint 的目的主要是為了提高我們的代碼質量。通常我們提高代碼質量的方式是通過 CodeReview,但是這個過程耗費的人工和時間往往較大,所以我們想通過 OCLint 的一些規則,讓機器幫我們完成一部分代碼質量的檢測,從而提高我們的工作效率。
    參考鏈接:

    iOS 工程自動化 - OCLint

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容