1. 程式人生 > >Android Jenkins+Git+Gradle持續整合-實在太詳細

Android Jenkins+Git+Gradle持續整合-實在太詳細

轉載自:http://www.jianshu.com/p/38b2e17ced73/

在專案的上個版本,老大說將Android打包搞到伺服器上,讓所有人都可以享受打包的樂趣,接著就有了這篇文章~Jenkins自動打包,已經用了一段時間了,奈何前段時間陷入了王者峽谷,所以一直懶得寫文章,現在終於找回狀態,開擼。雖然Jenkins的文章又很多,但我覺得這篇會給你幾乎所有想要的。
我用的是Jenkins+Git+Gradle實現自動打包

安裝

上來就是乾的,首先到Jenkins的官網下載https://jenkins.io,點選Download Jenkins按鈕會彈出兩個版本選擇:LTS Release(長期支援版本),Weekly Release(每週更新版本)。首先說一下這兩個版本,個人覺得和MIUI的更新類似,一個開發版本一個穩定版,大家可以自行選擇,功能上幾乎沒區別。點選尖角號

會彈出作業系統,可以選擇對應的作業系統安裝,也可以直接下載2.xx.x.war包然後放在Tomcat(下文會詳細介紹Tomcat一些功能)的webapps目錄,新建Jenkins資料夾再放入。

我選擇的是Windows安裝版的,首先安裝版和war版我都嘗試過,功能是沒區別的,主要的區別在於目錄上,安裝版指定安裝目錄以後幾乎所有的東西都會在對應的資料夾下生成,比如Jobs(即存放工程目錄),不會在其他磁碟再生成多餘的資料夾,而war版放在Tomcat目錄下以後,用瀏覽器開啟,所有的東西會在C盤生成.Jenkins資料夾。我自己是有一些強迫症的,喜歡目錄整潔,不生成多餘資料夾的。還有一個理由就是安裝版可以不依賴Tomcat,即使本機沒有安裝Tomcat,安裝版安裝完成後依然可以用本機ip:port

啟動。大家可以自行選擇喜歡的版本。

由於安裝部分比較簡單,就不上圖了。

外掛

1.進入管理外掛

接下來就要說說,Jenkins最強大的部分之一了,那就是外掛。Jenkins提供了非常多的外掛,幾乎你想要的外掛全有,前提是你能找的到~官網提供了外掛搜尋功能,選擇Plugins頁就可以各種搜尋了。

重點來了(敲黑板,啪啪啪~):首次進入,首先要輸入一個金鑰來進入Jenkins,接下來...接下來...上圖


setup.png


一般選擇第一項即可,會自動安裝推薦的外掛,注意:這裡並不是所有外掛都能安裝成功,有的安裝失敗也不影響,所有的安裝完進行下一步就可以了。

But,有時候點選以後會發生下面的情況


setup_error.png


怎麼點選Retry按鈕依然是錯誤,這時候不要慌張,咱們選擇第一張圖中的第二項,進行自己選擇,這裡系統推薦的外掛預設也是選中的,直接點安裝即可。But,個別情況依然會出現上圖的錯誤頁面,那麼解決辦法就是:進入自行選擇頁面,清空選項即所有都不選,然後點安裝按鈕,進入下一頁。

下一頁就是建立使用者頁面,這裡建議建立使用者,下面提供了Continue as admin按鈕也可進入主頁,但是後期想建立使用者還是很麻煩的,所以建議建立使用者。

建立好使用者,就可以進入到主頁了~選擇系統管理->管理外掛->可選外掛來開始安裝我們需要的外掛。

2.外掛列表

注意:列表中為主要外掛,而Jenkins的外掛是有依賴關係的,安裝一個外掛可能要先安裝它依賴的外掛,否則會安裝失敗。在可選外掛勾選列表中的外掛即可,依賴外掛會自動下載,是不是很棒。

1.Global Tool Configuration

在系統管理選項中找到Global Tool Configuration進入,如果上面的外掛安裝成功,在這裡會看到三個板塊,如圖


Global_Tool_Configuration.png


分別是JDK,Git,Gradle板塊,分別配置這三個的路徑。

  • JDK:別名=任意,JAVA_HOME=JDK目錄
  • Git:別名=任意, Path to Git executable=Git安裝目錄\bin\git.exe
  • Gradle:別名=任意,GRADLE_HOME=Gradle下載目錄\Gradle\gradle-2.xx
    Gradle儘量配置多個,因為專案的gradle版本可能不一樣,所以需要選擇不同的Gradle版本進行編譯

這個Gradle的目錄,可以是Android Studio預設下載的Gradle目錄,在使用者目錄的.gradle\wrapper\dists資料夾下,但是目錄不是很整潔;也可以到http://www.androiddevtools.cn找到gradle資源處下載常用的gradle版本,放到一個指定的資料夾,然後配置路徑即可,目錄比較整潔。

2.全域性屬性

在這裡最好配置一下全域性屬性,這裡先說一個,就是配置Android SDK目錄,在打包是有可能會出現ANDROID_HOME not found的情況,所以在系統管理->系統設定->全域性屬性版塊勾選上Environment variables選項,然後新增


android_home.png


記得更改值內的路徑為本機sdk目錄。

注意:這裡的鍵需要和本機環境變數內的Android SDK目錄的鍵一致

打包

1.建立專案

距離開始打包又近了一步,接下來就開始建立新專案了,點選首頁的新建,進入下圖介面


create.png


給自己的專案起個名字,然後選擇構建一個自由風格的軟體專案,點選OK按鈕,進入專案的配置介面。

2.專案配置

直接選擇原始碼管理tab或者向下滾動找到原始碼管理,如圖;


source_manage.png


選中Git選項,會出現上圖的介面,配置Git專案的URL,我測試用的是Github專案,並且傳輸協議選擇的是HTTP,需要選擇Credentials選項,選擇通行證,第一次需要點選Add新增通行證,如圖:


credentials.png


Kind種類選擇預設的Username with password,然後在Username和Pasword處分別輸入Git賬戶的使用者名稱和密碼,然後滾動到下方點選Add,然後在Credentials中選擇我們剛才新增的通行證。

接著滾動到構建Tab,點選新增構建步驟,然後選擇Invoke Gradle script,如圖:


build.png


然後配置構建時的Gradle版本,和需要執行的任務,如圖:


build1.png


這個Tasks是先clean工程,然後打包所有渠道的Release版本,這是Gradle的命令,不多說了。然後點選儲存按鈕,馬上就可以打包了。

3.開始構建

點選儲存後,進入專案介面,如圖:


project.png


點選左側選單欄的立即構建,開始構建專案,這時候Build History版塊會出現構建任務列表,點選進入可以檢視構建詳情頁,如圖


project_build.png


又很多選單可以選擇來檢視狀態,點選Console Output來檢視構建輸出的日誌,所有的資訊都會顯示,日誌最後輸出Finished: SUCCESS即構建成功。

成功之後,返回專案地址就可以點選工作空間,在app的build目錄下面檢視apk生成情況。

以上就是Jenkins打包最簡單的配置,我知道大家想要的不止這些,更精彩的還在後面。

定製想要的功能

1.引數化構建

在我們打包的時候,我們大多時候不想只是簡簡單單打一個版本的包,我們想通過配置一下引數,來滿足一些需求,比如根據渠道打不同版本的包、根據Tag打不同的包等,下面就來說一下Jenkins引數化構建。

在我們專案中需要配置的選項有:版本(Release 或 Debug),版本號,渠道包,根據Tag打包。另外我們還需要加上打包途徑,AS打包還是Jenkins打的包,還要加一個時間戳。所有的引數列出來了,下面就配置Jenkins的引數化構建吧~

在Jenkins專案主頁選擇配置,進入配置頁,在General tab將引數化構建過程選中,如圖:


General.png


接下來就可以新增引數了,下面我先列出引數表格:

引數名 引數型別 引數值列表
BUILD_TYPE Choice Release or Debug
IS_JENKINS Choice true
PRODUCT_FLAVORS Choice Xiaomi 、Wandoujia等
BUILD_TIME Dynamic Parameter 2016-12-21-11-11
APP_VERSION Choice 1.0.0、1.0.1等
GIT_TAG Git Parameter tag1.0.0等

下面直接放我的配置截圖:


build_type.png
product_flavor.png
app_version.png
is_jenkins.png
build_time.png
git_tag.png


配置完引數還不算完,我們要在下方構建時候引用,首先找到構建標籤處,將Tasks屬性值修改為:

clean assemble${PRODUCT_FLAVORS}${BUILD_TYPE} --stacktrace --debug

其中${PRODUCT_FLAVORS}&{BUILD_TYPE}分別對應上面的引數名。配置如圖:


build2.png


看了圖大家肯定留意到了紅色框內的選項而且很好奇吧,這個選項是APP_VERSION、IS_JENKINS、BUILD_TIME需要用到的,因為這三個引數需要注入到Android專案中的配置一樣,而紅色框中的這個選項可以幫我們侵入到gradle.properties檔案中替換值,並且build.gradle檔案能夠直接引用gradle.properties檔案中的屬性,所以起到了侵入的效果。下面分別是我的gradle.properties和主專案的build.gradle檔案全程式碼:

//gradle.properties

# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
#http://www.gradle.org/docs/current/userguide/multi_project_builds.html
#sec:decoupled_projects
#org.gradle.parallel=true
APP_VERSION=1.0.1
IS_JENKINS=true
BUILD_TIME=''

//build.gradle

apply plugin: 'com.android.application'
def getDate() {    
    def date = new Date()    
    def formattedDate = date.format('yyyy-MM-dd-HH-mm')    
    return formattedDate
}
def verCode = 14
android {    
    compileSdkVersion 25    
    buildToolsVersion "25.0.0"    
    defaultConfig {        
        applicationId "com.zyyoona7.autobuildtest"        
        minSdkVersion 15        
        targetSdkVersion 23        
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"        
        multiDexEnabled true        
        versionCode verCode        
        versionName APP_VERSION    
    }    
    signingConfigs {        
        signingConfig {            
            //由於本地打包使用的是本機上的KeyStore            
            //而Jenkins打包用的是伺服器上的KeyStore            
            //兩個路徑不一樣           
            if("true".equals(IS_JENKINS)){                
                storeFile file("伺服器上KeyStore的路徑")            
            }else {                
                storeFile file(STORE_FILE_PATH)            
            }            
            keyAlias KEY_ALIAS            
            keyPassword KEY_PASSWORD            
            storePassword STORE_FILE_PASSWORD        
        }    
    }    
    buildTypes {        
        release {           
            minifyEnabled true            
            zipAlignEnabled true            
            shrinkResources true            
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'            
            signingConfig signingConfigs.signingConfig        
        }        
        debug {  }    
    }    
    dexOptions {        
        javaMaxHeapSize "2g"    
    }    
    //渠道Flavors   
    productFlavors {        
        wandoujia {            
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]        
        }        
        xiaomi {            
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]        
        }    
    }    
    //修改生成的apk名字及輸出資料夾    
    applicationVariants.all { variant ->        
        variant.outputs.each { output ->            
            //新名字            
           def newName            
           //時間戳            
           def timeNow            
           //輸出資料夾            
           def outDirectory            
           //是否為Jenkins打包,輸出路徑不同           
            if ("true".equals(IS_JENKINS)) {                
               //Jenkins打包輸出到伺服器路徑                
               timeNow = BUILD_TIME                
               //BUILD_PATH為伺服器輸出路徑                
               outDirectory = BUILD_PATH                
               //AutoBuildTest-v1.0.1-xiaomi-release.apk                
               newName = 'AutoBuildTest-v' + APP_VERSION + '-' + variant.productFlavors[0].name + '-' + variant.buildType.name + '.apk'            
           } else {                
               //本機打包輸出在本機路徑                
               timeNow = getDate()                
               outDirectory = output.outputFile.getParent()                
               if ('debug'.equals(variant.buildType.name)) {                    
                   newName = "AutoBuildTest-v${APP_VERSION}-debug.apk"                
               } else {                    
                   //AutoBuildTest-v1.0.1-xiaomi-release.apk                    
                   newName = 'AutoBuildTest-v' + APP_VERSION + '-' + variant.productFlavors[0].name + '-' + variant.buildType.name + '.apk'                
               }            
           }            
           output.outputFile = new File(outDirectory+'/'+timeNow, newName)        
       }    
    }
}

dependencies {    
    compile fileTree(dir: 'libs', include: ['*.jar'])    
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {        
        exclude group: 'com.android.support', module: 'support-annotations'    
    })    
    compile 'com.android.support:appcompat-v7:25.0.0'    
    testCompile 'junit:junit:4.12'
}

這樣在Jenkins打包的時候上面三個引數就會隨著選擇變化而變化了。

GIT_TAG引數使用配置,只需在原始碼管理處的Branch引用改為$GIT_TAG引用引數名,如圖:


git_tag_use.png


引數配置完畢,看一下主頁面的效果吧,現在立即構建選項變成了 Build with Parameters,完成圖:


build_with_parameters.png

提示:

  • 如果選中了GIT_TAG中的任意版本都無法取消選中,只能重新整理;
  • 還有使用GIT_TAG時最好選擇tag版本大於等於支援Jenkins打包的版本,因為之前版本程式碼中沒加需要侵入的屬性

2.按時打包

3.構建命名

每次構建的時候,Build History模組顯示是這樣的,如圖:


build_history.png


每次構建都只顯示數字(#xx),這樣很不好看,我們想要它顯示更多的資訊怎麼辦呢?比如加入構建者姓名、構建的app版本、構建的型別等。請看下圖:


set_build_name.png


配置完以後再次打包,變成了這個樣子,如圖:


build_history1.png


是不是很Nice,當然大家還可以根據需求自行發揮~

4.Tomcat配置下載地址

打完包放在伺服器上,我們得配置一下下載環境才能下載,首先是Tomcat的安裝,這裡對Tomcat安裝就不做詳細的介紹了,如果不熟悉的請自行谷歌或百度,下面內容需基於Tomcat環境進行,我的Tomcat版本為8.0+。

這裡說一下如何使用Tomcat配置下載地址,首先進入Tomcat目錄下的conf資料夾,然後開啟server.xml檔案在最後新增如圖程式碼:


erver.png
<!-- docBase為絕對路徑即板寸apk檔案的資料夾,path為相對地址即在位址列訪問的地址-->
<Context  reloadable="true" docBase="C://android/downloadApk" crossContext="true" path="/downloadApk"/>

新增完這句話以後啟動Tomcat服務,開啟瀏覽器輸入IP:Port/downloadApk,就可以訪問了點選你想要的檔案下載吧。

5.二維碼下載

二維碼下載功能,現在網上大多數的做法是通過蒲公英或者fir.im來生成二維碼,這兩個都是內測平臺,我體驗過蒲公英,需要將檔案傳到蒲公英網站然後他們生成二維碼返回,傳到別處總感覺怪怪的,於是我決定自己生成二維碼然後放在下載地址的資料夾中,通過連結顯示。

新增python的環境變數到Jenkins的環境變數中,文章前面有提到過,在系統管理->系統設定中,如圖新增python環境變數:


python.png


注意:鍵名需要和電腦上系統環境變數內的鍵名保持一致。

然後開啟專案配置頁面,在構建版塊點選新增構建步驟,如圖:


add_build.png


在編輯框內輸入專案的使用命令


python_build.png

注意:下載地址需要自己拼接,生成路徑也需要自己拼接。

這樣每次打包後都會在生成apk的資料夾內生成一個對應的二維碼。掃一掃就可以下載啦~~~

6.構建後操作

構建完成後,我希望將下載地址和二維碼放在Build History的版塊中,方便下載,那麼我們就來設定一下,開啟專案配置頁,如圖操作:


build_after.png


Description輸入框內新增

<!-- 需替換連結地址 -->
![](http:/192.168.1.88:8088/downloadApk/${BUILD_TIME}/qrcode.png)<br>
<a href="http://192.168.1.88:8088/downloadApk/${BUILD_TIME}/AutoBuildTest-v${APP_VERSION}-${PRODUCT_FLAVOR}-${BUILD_TYPE}.apk">下載連線</a>

7.郵件通知

打完包,我想通知需要下載的人怎麼辦?發郵件~~Jenkins自帶了郵件功能,但是不太好用,所以我選擇了Email Extension Plugin這個外掛來實現發郵件功能(已經在外掛列表中)。進入系統管理->系統設定頁面,如圖:



mail.png


郵件格式:

[Jenkins構建通知]$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!

(郵件由Jenkins自動發出,請勿回覆~)<br>
專案名稱:$PROJECT_NAME<br>
構建編號:$BUILD_NUMBER<br>
構建狀態:$BUILD_STATUS<br>
觸發原因:${CAUSE}<br>
構建地址:<A HREF="${BUILD_URL}">${BUILD_URL}</A><br>
構建輸出日誌:<a href="http://192.168.1.201:8090/job/${PROJECT_NAME}/${BUILD_NUMBER}/console">http://192.168.1.201:8090/job/${PROJECT_NAME}/${BUILD_NUMBER}/console</a><br>
下載地址:<a href="http://192.168.1.88:8088/downloadApk">http://192.168.1.88:8088/downloadApk</a><br><br>
二維碼下載:![](http://192.168.1.88:8088/downloadApk/${BUILD_TIME}/qrcode.png)<br>
最近修改:<br>${CHANGES, showPaths=false, format="%a:\"%m\"<br>", pathFormat="\n\t- %p"}

最終的效果圖是介個樣子的:


mail1.png

遇到的錯誤

1.AAPT err(Facade for 26390200):build-tools/23.0.1/aapt: /lib/libc.so.6: version `GLIBC_2.11' not found /23.0.1/aapt)

在將Jenkins部署到linux伺服器的時候出現了這個錯誤,lib/libc.so.6是linux系統的c庫,由於我們公司伺服器的linux系統太老,導致最高支援GLIBC_2.5,雖然可以通過升級核心來解決,但是有風險,所以最後決定還是部署到了Windows伺服器上面。所以在部署到Linux伺服器上面之前先檢查你的Linux系統所支援的GLIBC_2.xx的版本,Android Build-Tools 25.0.0的需要GLIBC_2.14

2.local.properties:sdk.dir not found or ANDROID_HOME not found

不好意思,因為沒及時記錄所以這個錯誤我只記了大概,而且配置完以後,想出現這個錯誤竟然沒復現,所以只能看個大概了。這個錯誤主要是配置Android SDK路徑為ANDROID_HOME環境變數沒有配置。Windows上面配置一下環境變數;名字ANDROID_HOME:值為Android SDK路徑。還有一種方法,配置Jenkins的環境變數名字和值和上面一樣,新增到系統管理->系統設定->全域性屬性下面有一個Environment variables 勾上,然後新增環境變數即可

總結

Jenkins打包並不難,最難的地方就是安裝外掛,由於公司網路不太給力導致安裝外掛至少半天,坑啊~~~

如果在Linux系統上和Mac上使用Jenkins的化設定起來幾乎無差別,只是需要的檔案格式大同小異而已。

由於篇幅比較多,希望大家看完多多反饋,有什麼問題也可以留言。

參考