引言
在個推SDK 開發過程中,通常而言一個完整的開發上線流程是這樣的:提出需求-> 需求開發 -> 打包測試 -> 問題修復 -> 打包交付測試驗證 -> 測試透過 -> 產品上線。
在這個流程中,不難發現打包是一項重複性勞動,而且我們常常會重複經歷問題修復階段,也就意味著我們在一個開發上線週期內需要進行多個重複性的打包過程。如果能最佳化這個環節,那麼開發效率就能得到顯著提升。
除此之外,手動打包往往還容易引入一些風險,比如說打包環境不一致、簽名檔案洩漏、效率低、包的溯源管理困難等等,所以我們需要一套持續整合的方案來減少這種重複性勞動以及規範打包流程。Jenkins作為持續整合的方案,擁有豐富的外掛支援,以下我們將為大家介紹個推基於Jenkins的構建實踐經驗。
Jenkins 簡介Jenkins 是一款開源的 CI&CD 軟體,用於自動化各種開發任務,包括構建、測試和部署軟體等。Jenkins 支援多種執行方式,比如透過系統包、Docker 或者獨立的 Java 程式的執行。
開發者可以透過選擇流水線的方式來建立一個 PipeLine 構建任務,如下:
透過建立 Jenkinsfile 進行版本控制,如下:
Jenkins Pipeline 允許你像寫程式碼一樣管理你的構建指令碼。我們通常可以透過建立 Jenkinsfile 控制版本從而更好地進行功能的更新迭代。一個宣告式流水線語法的基本結構如下:
pipeline { agent any stages { stage('Build') { steps { // } } stage('Test') { steps { // } } stage('Deploy') { steps { // } } }}
pipeline 和agent分別是宣告式流水線的兩種特定語法,後者為流水線指定了一個特定的工作區。stages 由多個不同的stage組成,stage可以展示在 stage view 中,用來表示構建環節中的不同階段。steps我們可以理解成每個構建階段中包含的不同步驟。通常我們的構建指令可以在這裡編寫。
接下來本文將介紹關於個推使用 Jenkins 持續整合方案的實踐(本文基於 Jenkins 2.19,使用 Jenkins Pipeline 構建)。
需求分析以個推的實踐經驗來分析,在打包過程中,我們最好能有一種控制程式碼風險的機制,這種機制能夠自動化地控制有關風險程式碼進入打包環節,並中斷打包流程,給出風險警示。另外,中大型專案的模組依賴往往比較複雜,我們應提供一種按需依賴組合的方式。研發人員還可以引入一些自動化測試,保證程式碼的質量。綜上所述,一個打包方案的需求分析如下:
程式碼檢測:在多人開發中,除了程式碼 review,我們還需要在構建階段引入一定的程式碼檢測機制,對一些風險程式碼進行掃描檢測,比如記憶體洩漏、不可退出迴圈等等,以規避此類程式碼打包上線。模組組合:個推 SDK 有許多不同的功能業務模組,但是一些模組並非打包所必須,所以在打包的過程中研發人員需要根據不同的需求將相應的模組組合打包,輸出產物。單元測試:為了在一定程度上規避問題程式碼的上線,在構建之前,我們需要先對程式碼進行單元測試。只有通過了單元測試才能繼續進行SDK構建。SDK 構建:個推 SDK 經常會有一些定製需求,而這些定製需求的功能類似,所以我們可以根據不同的定製需求,結合個推的預編譯外掛,選擇編譯不同的程式碼,以減少開發成本。Jar/AAR 檔案合規性檢驗:對 SDK 來說,構建輸出的產物一般為 aar 或 jar 檔案。為保證輸出的檔案合規性,我們需要對輸出產物的格式(包括版本號、域名等資訊)做最終的檢測。真機自動化測試(可選):如果我們希望生成的 SDK 可以在真機上模擬執行測試,則可以選擇這個步驟。資料包歸檔:由於我們最後輸出的檔案包含整合文件、demo 等等,所以構建的最後階段,我們需要將這些資原始檔進行歸檔並放到指定的目錄下。通知構建者:有些時候構建可能需要一定的時間,構建者會非同步地去處理其他事情。當構建完成的時候,我們需要通知相關的構建人員。根據上述需求的分析,一個完整的持續整合流程圖如下所示:
首先,進入準備階段(prepare), 在該階段會進行打包前的準備工作,比如環境準備等。接著是解析編譯打包相關引數(parse jenkinsConfig), 用於之後的打包構建,包括模組依賴組合的支援等。
然後是拉取相關打包程式碼(checkout code)階段。隨後進入程式碼檢測(Android Lint)階段和單元測試階段(Unit Testing)。透過前面的單元測試以及程式碼檢測之後就可以進入我們的編譯 SDK 階段(Build SDK)了, 在該階段我們可以配合個推的預編譯外掛以及相關的打包環境變數引數,選擇相對應的模組組合或者選擇對應的功能程式碼進行按需編譯。
編譯完成後,我們需要對相關的輸出產物(JAR/AAR)進行格式檢測(CheckJar 階段)。待檢測透過就可以進行真機模擬測試了(Automated Testing 階段,可選),隨後就可以輸出構建產物(PrintSDK 階段)併發送郵件通知相關構建人員(Email Notification 階段)。至此,一次完整的打包流程已經結束。
Android 構建環境管理上文介紹了打包構建方案的流程,但是在實踐中,我們會發現隨著構建的任務越來越多,構建的環境會變得越來越繁雜,難以管理。
痛點分析:當我們依賴於宿主機構建 Android 時,不同的專案有著不同的 gradle 環境。隨著 gradle 的升級、專案的迭代,當不同的構建專案任務數量越來越龐大時,宿主機的 gradle 環境就越容易出現汙染。另外,由於構建的環境依賴宿主機的編譯環境,一旦宿主機的編譯環境發生變化,就很容易對構建專案產生影響。
為解決這個問題,我們可以將不同的 Android gradle 構建環境放進一個 Docker 容器中。Docker 是一個開源的應用容器引擎,可以實現虛擬化,也可以由開發者打包應用或者依賴包到一個輕量級、可移植的容器,然後釋出至不同的機器上。容器完全使用沙箱機制,相互之間不會有任何介面(類似 iPhone 的 App), 更重要的是容器效能開銷極低。
在每次編譯構建時我們都依賴於一個 Docker 容器的環境,透過這種方式將任務之間的編譯環境以及與宿主機之間透過 Docker 容器隔離開來,這樣可以保證宿主機的環境變化對編譯任務不產生影響,保證構建環境的乾淨。再之後隨著 gradle 版本升級,我們需要升級併發布對應的Docker映象版本,以相容高版本的編譯環境、做相應的環境版本管理。
Jenkins Pipeline 提供了使用 Docker 映象作為構建環境的功能,程式碼如下:
pipeline { agent { docker { image 'allbears/jenkins-android:1.0.1' } }}
維護和擴充套件
使用 Pipeline 構建時,開發者可以透過維護 Jenkinsfile對打包功能進行版本管理。這種構建方式更方便,開發者可以自由地迴歸歷史版本進行打包。Jenkinsfile 的大致結構模板如下。
pipeline{ agent { docker { image 'allbears/jenkins-android:1.0.1' //指定構建環境 } } stages { stage('Prepare'){ steps { echo "構建前準備" } } stage('Parse Jenkins Config'){ steps { echo "Jenkins 構建引數解析" } } stage('Checkout Code'){ steps { echo "構建程式碼檢出" } } stage('Android Lint'){ steps { echo "程式碼靜態檢測" } } stage('Unit Testing') { steps { echo "單元測試" } } stage('Clean') { steps { echo "編譯前環境初始化" } } stage('Build SDK') { steps { echo "構建 SDK" } } stage('Check JAR') { steps { echo "Jar 包合規性分析" } } stage('Automated Testing') { steps { echo "自動化測試" } } stage('Print SDK') { steps { echo "構建產物歸檔" } } stage('Email Notification') { steps { echo "郵件通知" } } }}
從上述的 Jenkinsfile 中我們不難得知,每個流水線會由不同的 stage 組成,而每一個 Stage 則可以作為一個獨立的小功能模組。開發者可以透過將不同的 stage 進行排列組合來進行相應的擴充套件。
總結人工構建過程繁瑣、操作耗時,還容易在手動打包過程中引入一些風險。個推使用 Jenkins 自動化構建免去了繁瑣的人工操作過程,充分解放了研發人員的生產力。此外,個推使用Pipeline方式“持續整合”構建,讓研發人員管理、迭代構建工程更加方便。
最後在這裡我也分享一份由幾位大佬一起收錄整理的Android學習PDF+架構影片+面試文件+原始碼筆記,高階架構技術進階腦圖、Android開發面試專題資料,高階進階架構資料
這些都是我閒暇時還會反覆翻閱的精品資料。可以有效的幫助大家掌握知識、理解原理。當然你也可以拿去查漏補缺,提升自身的競爭力。
相信一定可以幫助大家!