1. 程式人生 > >使用Jenkins生成 二維碼

使用Jenkins生成 二維碼

背景描述

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

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

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

Overview of Jenkins Job
Build view of Jenkins Job

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

  • 定期對GitHub倉庫進行檢測,若有更新則自動執行構建打包;
  • 構建成功後根據ipa/apk生成二維碼,並可在歷史構建列表中展示各個版本的二維碼,通過手機掃描二維碼可直接安裝對應版本;
  • 在構建結果頁面中展示當次構建的成果物(Artifact,如.ipa.app.apkinfo.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 URLSSH URL均可。不過需要注意的是,Credentials要和Repository URL對應,也就是說:

  • 如果Repository URLHTTPS URL形式的,那麼Credentials就要採用GitHub使用者名稱密碼的校驗方式;而且,如果在GitHub中開啟了2FA(two-factor authentication),那麼還需要在GitHub中建立一個Personal access token,輸入密碼時將這個Personal access token作為密碼進行輸入。
  • 如果Repository URLSSH URL形式的,那麼就需要先在Jenkins所在的伺服器上建立一個SSH祕鑰對,並將公鑰新增到GitHub的SSH keys中,然後在填寫Credentials時,選擇SSH Username with private key的校驗方式,填入GitHub Username、SSH私鑰、以及建立SSH祕鑰對時設定的Passphrase

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

在配置Branches to build時,可以採用多種形式,包括分支名稱(branchName)、tagNamecommitId等。其中分支名稱的形式用的最多,例如,若是構建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頁面中,同時也會顯示在歷史構建列表中。

有了這個前提,要將二維碼圖片展示在歷史構建列表中貌似就可以實現了,能直觀想到的方式就是採用HTMLimg標籤,將<img src='qr_code_url'>寫入到build描述資訊中。

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

這是因為Jenkins出於安全的考慮,所有描述資訊的Markup Formatter預設都是採用Plain text模式,在這種模式下是不會對build描述資訊中的HTML編碼進行解析的。

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

更改配置後,我們就可以在build描述資訊中採用HTMLimg標籤插入圖片了。

另外還需要補充一個點。如果是使用蒲公英(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中,然後針對具體的專案修改少量配置資訊,即可將這一套持續整合打包平臺執行起來,實現和文章開頭插圖中完全相同的功能效果。