準備工作
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
倉庫地址
驗證方式(用戶名密碼或ssh)
分支(想要構建的分支名稱,圖中傳了一個自定義的參數)
gitlab hook
- 在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
:配置后覆蓋默認的超時時限。
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選項
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 的一些規則,讓機器幫我們完成一部分代碼質量的檢測,從而提高我們的工作效率。
參考鏈接:
-
xcpretty -- 對xcodebuild的輸出進行格式化
-
altool -- 命令行工具提交AppleStore
參考鏈接:
https://itunesconnect.apple.com/docs/UsingApplicationLoader.pdf -
Jenkins + Docker(適配規模較大,代碼提交頻繁(意味著構建頻繁)