使用Jenkins搭建iOS/Android持續集成打包平臺

根據項目需求,現要在團隊內部搭建一個統一的打包平臺,實現對iOS和Android項目的打包。而且為了方便團隊內部的測試包分發,希望在打包完成后能生成一個二維碼,體驗用戶(產品、運營、測試等人員)通過手機掃描二維碼后就能直接安裝測試包。

該需求具有一定的普遍性,基本上所有開發APP的團隊都可能會用到,因此我將整個需求實現的過程整理后形成此文,并且真正地做到了零基礎上手,到手即飛、開箱即用,希望能對大家有所幫助。

首先,先給大家展示下平臺建設完成后的整體效果:

該平臺主要實現的功能有3點:

定期對GitHub倉庫進行檢測,若有更新則自動執行構建打包;

構建成功后根據ipa/apk生成二維碼,并可在歷史構建列表中展示各個版本的二維碼,通過手機掃描二維碼可直接安裝對應版本;

在構建結果頁面中展示當次構建的成果物(Artifact,如.ipa、.app、.apk、info.plist等文件),供有需要的用戶進行下載。

接下來,本文就開始對平臺建設的完整實現過程進行詳細介紹。

安裝Jenkins

Jenkins依賴于Java運行環境,因此需要首先安裝Java

安裝Jenkins的方式有多種,可以運行對應系統類型的安裝包,可以通過docker獲取鏡像,也可以直接運行war包。

我個人傾向于直接運行war包的形式,只需下載jenkins.war后,運行如下命令即可啟動Jenkins。

1$ nohup java -jar jenkins_located_path/jenkins.war --httpPort=88 &

如果不指定httpPort,Jenkins的默認端口為8080。

Jenkins插件

Jenkins有非常多的插件,可以實現各種功能的擴展。

針對搭建的iOS/Android持續集成打包平臺,我使用到了如下幾個插件。

GIT plugin

SSH Credentials Plugin

Git Changelog Plugin: 獲取倉庫提交的commit log

build-name-setter:用于修改Build名稱

description setter plugin:用于在修改Build描述信息,在描述信息中增加顯示QRCode(二維碼)

Post-Build Script Plug-in:在編譯完成后通過執行腳本實現一些額外功能

Xcode integration: iOS專用(可選)

Gradle plugin: Android專用(可選)

安裝方式也比較簡單,直接在Jenkins的插件管理頁面搜索上述插件,點擊安裝即可。

創建項目(Job)

在Jenkins中,構建項目以Job的形式存在,因此需要針對每個項目創建一個Job。有時候,一個項目中可能有多個分支同時在進行開發,為了分別進行構建,也可以針對每個分支創建一個Job。

創建Job的方式有多種,本次只需要創建Freestyle project類型的即可。

Main page->New Item->Freestyle project

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

配置Git代碼倉庫

要對項目進行構建,配置項目的代碼倉庫是必不可少的。由于當前我們的項目托管在GitHub私有倉庫中,因此在此需要對Git進行配置。

在【Source Code Management】配置欄目下,如果之前GIT 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就要采用GitHub用戶名密碼的校驗方式;而且,如果在GitHub中開啟了2FA(two-factor authentication),那么還需要在GitHub中創建一個Personal access token,輸入密碼時將這個Personal access token作為密碼進行輸入。

如果Repository URL是SSH URL形式的,那么就需要先在Jenkins所在的服務器上創建一個SSH秘鑰對,并將公鑰添加到GitHub的SSH keys中,然后在填寫Credentials時,選擇SSH Username with private key的校驗方式,填入GitHub Username、SSH私鑰、以及創建SSH秘鑰對時設置的Passphrase。

如果對Git權限校驗的概念還比較模糊,可以參考《深入淺出Git權限校驗》

在配置Branches to build時,可以采用多種形式,包括分支名稱(branchName)、tagName、commitId等。其中分支名稱的形式用的最多,例如,若是構建master分支,則填寫refs/heads/master,若是構建develop分支,則填寫refs/heads/develop。

除了以上關于Git的必填配置項,有時根據項目的實際情況,可能還需要對Jenkins的默認配置項進行修改。

比較常見的一種情況就是對clone的配置進行修改。

在Jenkins的默認配置中,clone代碼時會拉取所有歷史版本的代碼,而且默認的超時時限只有10分鐘。這就造成在某些項目中,由于代碼量本身就比較大,歷史版本也比較多,再加上網絡環境不是特別好,Jenkins根本沒法在10分鐘之內拉取完所有代碼,超時后任務就會被自動終止了(錯誤狀態碼143)。

這種問題的解決方式也很簡單,無非就是兩種思路,要么少拉取點代碼(不獲取歷史版本),要么提高超時時限。對應的配置在Advanced clone behaviours中:

Shallow clone:勾選后不獲取歷史版本;

Timeout (in minutes) for clone and fetch operation:配置后覆蓋默認的超時時限。

配置構建觸發器

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

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

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

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

定期進行構建(Build periodically)

根據提交進行構建(Build when a change is pushed to GitHub)

定期檢測代碼更新,如有更新則進行構建(Poll SCM)

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

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

MINUTE HOUR DOM MONTH DOW

MINUTE: Minutes within the hour (0-59)

HOUR: The hour of the day (0-23)

DOM: The day of the month (1-31)

MONTH: The month (1-12)

DOW: The day of the week (0-7) where 0 and 7 are Sunday.

通常情況下需要指定多個值,這時可以采用如下operator(優先級從上到下):

*適配所有有效的值,若不指定某一項,則以*占位;

M-N適配值域范圍,例如7-9代表7/8/9均滿足;

M-N/X或*/X:以X作為間隔;

A,B,C:枚舉多個值。

另外,為了避免多個任務在同一時刻同時觸發構建,在指定時間段時可以配合使用H字符。添加H字符后,Jenkins會在指定時間段內隨機選擇一個時間點作為起始時刻,然后加上設定的時間間隔,計算得到后續的時間點。直到下一個周期時,Jenkins又會重新隨機選擇一個時間點作為起始時刻,依次類推。

為了便于理解,列舉幾個示例:

H/15 * * * *:代表每隔15分鐘,并且開始時間不確定,這個小時可能是:07,:22,:37,:52,下一個小時就可能是:03,:18,:33,:48;

H(0-29)/10 * * * *:代表前半小時內每隔10分鐘,并且開始時間不確定,這個小時可能是:04,:14,:24,下一個小時就可能是:09,:19,:29;

H 23 * * 1-5:工作日每晚23:00至23:59之間的某一時刻;

配置構建方式

觸發策略配置好之后,Jenkins就會按照設定的策略自動執行構建。但如何執行構建操作,這還需要我們通過配置構建方式來進行設定。

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

該種方式的優勢是操作簡單,UI可視化,在場景不復雜的情況下可以快速滿足需求。不過缺點就是依賴于插件已有的功能,如果場景較復雜時可能單個插件還無法滿足需求,需要再安裝其它插件。而且,有些插件可能還存在一些問題,例如對某些操作系統版本或XCode版本兼容不佳,出現問題時我們就會比較被動。

我個人更傾向于另外一種方式,就是自己編寫打包腳本,在腳本中自定義實現所有的構建功能,然后在Execute Shell中執行。這種方式的靈活度更高,各種場景的構建需求都能滿足,出現問題后也能自行快速修復。

另外,對于iOS應用的構建,還有一個需要額外關注的點,就是開發者證書的配置。

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

構建后處理

完成構建后,生成的編譯成果物(ipa/apk)會位于指定的目錄中。但是,如果要直接在手機中安裝ipa/apk文件還比較麻煩,不僅在分發測試包時需要將好幾十兆的安裝包進行傳送,體驗用戶在安裝時也還需要通過數據線將手機與計算機進行連接,然后再使用PP助手或豌豆莢等工具進行安裝。

當前比較優雅的一種方式是借助蒲公英(pgyer)或fir.im等平臺,將ipa/apk文件上傳至平臺后由平臺生成二維碼,然后只需要對二維碼鏈接進行分發,體驗用戶通過手機掃描二維碼后即可實現快速安裝,效率得到了極大的提升。

上傳安裝包文件,生成二維碼

不管是蒲公英還是fir.im,都有對應的Jenkins插件,安裝插件后可以在Post-build中實現對安裝包的上傳。

除了使用Jenkins插件,fir.im還支持命令上傳的方式,蒲公英還支持HTTP Post接口上傳的方式。

我個人推薦采用命令或接口上傳的方法,并在構建腳本中進行調用。靈活是一方面,更大的好處是如果上傳失敗后還能進行重試,這在網絡環境不是很穩定的情況下極其必要。

Jenkins成功完成安裝包上傳后,pgyer/fir.im平臺會生成一個二維碼圖片,并在響應中將圖片的URL鏈接地址進行返回。

展示二維碼圖片

二維碼圖片的URL鏈接有了,那要怎樣才能將二維碼圖片展示在Jenkins項目的歷史構建列表中呢?

這里需要用到另外一個插件,description setter plugin。安裝該插件后,在【Post-build Actions】欄目中會多出description setter功能,可以實現構建完成后設置當次build的描述信息。這個描述信息不僅會顯示在build頁面中,同時也會顯示在歷史構建列表中。

這個方法的思路是正確的,不過這么做以后并不會實現我們預期的效果。

這是因為Jenkins出于安全的考慮,所有描述信息的Markup Formatter默認都是采用Plain text模式,在這種模式下是不會對build描述信息中的HTML編碼進行解析的。

要改變也很容易,Manage Jenkins->Configure Global Security,將Markup Formatter的設置更改為Safe HTML即可。

更改配置后,我們就可以在build描述信息中采用HTML的img標簽插入圖片了。

另外還需要補充一個點。如果是使用蒲公英(pyger)平臺,會發現每次上傳安裝包后返回的二維碼圖片是一個短鏈接,神奇的是這個短連接居然是固定的(對同一個賬號而言)。這個短連接總是指向最近生成的二維碼圖片,但是對于二維碼圖片的唯一URL地址,平臺并沒有在響應中進行返回。在這種情況下,我們每次構建完成后保存二維碼圖片的URL鏈接就沒有意義了。

應對的做法是,每次上傳完安裝包后,通過返回的二維碼圖片短鏈接將二維碼圖片下載并保存到本地,然后在build描述信息中引用該圖片在Jenkins中的地址即可。

收集編譯成果物(Artifacts)

每次完成構建后,編譯生成的文件較多,但是并不是所有的文件都是我們需要的。

通常情況下,我們可能只需要其中的部分文件,例如.ipa/.app/.plist/.apk等,這時我們可以將這部分文件單獨收集起來,并在構建頁面中展示出來,以便在需要時進行下載。

要實現這樣一個功能,需要在【Post-build Actions】欄目中新增Archive the artifacts,然后在Files to archive中通過正則表達式指定成果物文件的路徑。

設置完畢后,每次構建完成后,Jenkins會在Console Output中采用設定的正則表達式進行搜索匹配,如果能成功匹配到文件,則會將文件收集起來。

總結

本文主要是對如何使用Jenkins搭建iOS/Android持續集成打包平臺的基礎概念和實施流程進行了介紹。對于其中涉及到的執行命令、構建腳本(build.py),以及Jenkins的詳細配置,出于篇幅長度和閱讀體驗的考慮,并沒有在文中進行詳細展開。

為了實現真正的開箱即用,我將Jenkins的配置文件和構建腳本抽離出來形成一套模板,只需要導入到Jenkins中,然后針對具體的項目修改少量配置信息,即可將這一套持續集成打包平臺運行起來,實現和文章開頭插圖中完全相同的功能效果。
詳細內容請閱讀《關于持續集成打包平臺的Jenkins配置和構建腳本實現細節》------------

http://debugtalk.com/post/iOS-Android-Packing-with-Jenkins-details/
http://debugtalk.com/post/iOS-Android-Packing-with-Jenkins/

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

推薦閱讀更多精彩內容