1. 程式人生 > >android開發之Jenkins+Gradle實現android開發持續整合、多渠道打包

android開發之Jenkins+Gradle實現android開發持續整合、多渠道打包

需求:
我今天在專案上加了一個功能,那麼一個好的專案開發流程必然得跑單元測試,意思是:“改一次程式碼,需要手動跑一次單元測試,來檢驗程式碼在當前情況下是否能執行成功!”,但每次都需要手動跑的話就太累了,因為一個新增專案功能,我一天下來可能會改十幾次程式碼。

因此我們將目標鎖定一下,只要某個工具能實時監控,每當svn上專案版本更改後,我就自動構建,然後跑一次單元測試,當然也可以改成每天一次或者每小時一次來監控svn上專案版本更改情況(隨你配置,後面會講),這樣豈不是妙湛!

一、Jenkins簡介

Jenkins是一個開源專案,提供了一種易於使用的持續整合系統,使開發者從繁雜的整合中解脫出來,專注於更為重要的業務邏輯實現上。同時Jenkins能實現監控整合中存在的錯誤,提供詳細的日誌檔案和提醒功能,還能用圖表的形式形象地展示專案構建的趨勢和穩定性。Jenkins的前身是Hudson,是一個可擴充套件的持續整合引擎。

二、Jenkins安裝與配置

  • 安裝:將下載的jenkins.war包直接放到tomcat下的webapps目錄下,然後啟動tomcat即可安裝完成,接下來登入:http://localhost:8080/jenkins就能進入jenkins系統頁面,在此不說tomcat如何配置環境變數
  • 編碼問題:

    • 當你進入jenkins系統管理頁面,會出現如圖提示,可修改tomcat的server.xml配置,在Connector 標籤新增上 URIEncoding=”UTF-8” 。
      這裡寫圖片描述

    這裡寫圖片描述

  • 配置:

    • 點選“系統管理” –> “Configure Global Security”
      這裡寫圖片描述

      這裡寫圖片描述
      首先先新增一個administer使用者作為超級管理員,全部許可權都打勾,如圖admin使用者。儲存,重啟。用剛剛新增的超級管理員作為賬號名註冊一個賬號,即可擁有超級管理員許可權。
      這裡寫圖片描述

    • JDKGradle如果系統環境變數配置好的話就不用再配置,用預設的就行。
    • 郵件通知:點選“系統管理”–> “系統設定”
      這裡寫圖片描述

三、Jenkins Gradle外掛安裝

  • 點選“系統管理”–> “管理外掛” –> “可選外掛” 選中Gradle plugin外掛安裝重啟即可。
    這裡寫圖片描述
    這裡寫圖片描述
    這裡寫圖片描述

  • 設定代理
    這裡寫圖片描述

四、Jenkins新建任務

  • 點選“新建”
    這裡寫圖片描述

  • 選擇“原始碼系統”
    這裡寫圖片描述

    Repository URL: svn 的 的地址,如果輸入的地址需要輸入使用者名稱和密碼,將自動跳出紅色的提示資訊,點選”enter credential” 進入設定svn 使用者名稱。

  • 選擇“構建觸發器”

    來到了這一步,實屬不易,這裡就是我們的天堂,就能完成“每當svn上專案版本更改後,我就自動構建,然後跑一次單元測試,當然也可以改成每天一次或者每小時一次來監控svn上專案版本更改情況。

    這裡寫圖片描述

    • Build periodically:週期進行專案構建(它不關心原始碼是否發生變化)

    • Poll SCM:定時檢查原始碼變更(根據SCM軟體的版本號),如果有更新就checkout最新code下來,然後執行構建動作,這裡我選擇它

  • 選擇“日程表”
    這裡寫圖片描述

    第一個引數代表的是分鐘 minute,取值 0~59;
    第二個引數代表的是小時 hour,取值 0~23;
    第三個引數代表的是天 day,取值 1~31;
    第四個引數代表的是月 month,取值 1~12;
    第五個引數代表的是星期 week,取值 0~7,0 和 7 都是表示星期天。
    如H/5 * * * * 表示的就是每5分鐘檢查一次原始碼變化。

  • 選擇 “構建”,新增“Invoke Gradle script”
    這裡寫圖片描述
    這裡寫圖片描述
    這裡寫圖片描述
    Switches :即gradle 後面所接的命令。上面相當於執行gradle clean build命令。

  • 構建後操作:構建失敗可以傳送郵件通知
    這裡寫圖片描述
    這裡寫圖片描述

五、Gradle介紹

Gradle 是以 Groovy 語言為基礎,面向Java應用為主.基於DSL(領域特定語言)語法的自動化構建工具。現在已是android的預設構建工具了。

六、android build.gradle配置

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.6'//依賴
    }
}

apply plugin: 'android'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')//新增android依賴libs
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"
    //簽名
    signingConfigs {
        myConfig {
            storeFile file("debug.keystore")
            storePassword "android"
            keyAlias "androiddebugkey"
            keyPassword "android"
        }
    }

    defaultConfig {
        versionCode 1
        versionName getVersionName()
        minSdkVersion 8
        targetSdkVersion 17
    }

    //渠道
    productFlavors {
        google{

        }
        tantai{

        }
    }

    buildTypes{
        release {
            signingConfig signingConfigs.myConfig
            runProguard true
            proguardFile 'proguard.cfg'
        }
    }

    sourceSets {
        main {
            manifest {
                srcFile 'AndroidManifest.xml'
            }
            java {
                srcDir 'src'
            }
            res {
                srcDir 'res'
            }
            assets {
                srcDir 'assets'
            }
            resources {
                srcDir 'src'
            }
            aidl {
                srcDir 'src'
            }
        }
    }
}


tasks.withType(Compile) {
    options.encoding = "UTF-8"
}
//替換AndroidManifest.xml的UMENG_CHANNEL_VALUE字串為渠道名稱
android.applicationVariants.all{ variant -> 
    variant.processManifest.doLast{ 
        copy{
            from("${buildDir}/manifests"){
                include "${variant.dirName}/AndroidManifest.xml"
            }
            into("${buildDir}/manifests/$variant.name")

            filter{
                String line -> line.replaceAll("UMENG_CHANNEL_VALUE", "$variant.name")
            }

            variant.processResources.manifestFile = file("${buildDir}/manifests/${variant.name}/${variant.dirName}/AndroidManifest.xml")
        }    
   }
}

遇到的問題:tomcat下gradle 構建如果遇到Could not load Logmanager “org.apache.juli.ClassLoaderLogManager”。

解決:註釋掉catalina.bat裡面的set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%即可!

注意:Gradle外掛能配置成功的前提是:“你的專案中是由Gradle構建的,否則免談”,Jenkins只是構建,得配合Gradle才能跑單元測試

七、手動跑單元測試

  • 選擇專案:
    這裡寫圖片描述
  • 點選“立即構建”
    這裡寫圖片描述
  • 點選“#1 / #2 …”檢視執行情況
  • 點選“Console Output”–控制檯輸出
    這裡寫圖片描述

八、Gradle實現的兩種簡單的多渠道打包方法

目前我掌握的方法有兩種,都非常簡單,用的都是Gradle Android外掛裡的productFlavors。

以友盟的多渠道打包為例,假設我們需要打包出如下渠道:UMENG, WANDOUJIA, YINGYONGBAO。

第一種方法,是需要建立檔案的:

我們在寫完我們的程式碼之後,在app/src下面,分別建立和main同級目錄的資料夾umeng, wandoujia, yingyongbao,這三個資料夾裡面都各只有一個AndroidManifest.xml檔案,檔案程式碼只需要如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="your.package.name">  
    <application>  

          <meta-data android:name="UMENG_CHANNEL" android:value="UMENG"/>  

    </application>  
</manifest> 

注意,上面的value的值要和你的渠道名所對應。比如wandoujia裡面要對應為你豌豆莢上的渠道名(如WANDOUJAI)。
然後在你的build.gradle的android{}節點裡面,新增productFlavors節點,程式碼如下:

android {  
    // 這裡是你的其他配置  

    productFlavors{  
        umeng{  }  
        wandoujai {  }  
        yingyongbao{  }  
    }  
    // 你的其他配置  
}  

注意這裡的flavors的名字要和你的資料夾的名字對應。這樣配置之後,構建的就是多渠道的APK了。

第二種方法,不用建立那些檔案的:

它使用的是Gradle Android外掛裡的另一個功能:manifestPlaceholders。

在這種方法中,你只需要在AndroidManifest.xml中,對友盟的渠道進行這樣配置:

<meta-data  
    android:name="UMENG_CHANNEL"  
    android:value="${CHANNEL_NAME}" />  

然後同樣使用productFlavors,不過這時它的配置是這樣的:

android {  
    // 你的其他配置程式碼  

    productFlavors {  
        yingyongbao {  
            manifestPlaceholders = [ CHANNEL_NAME:"YINGYONGBAO"]  
        }  
        umeng {  
            manifestPlaceholders = [ CHANNEL_NAME:"UMENG" ]  
        }  
        wandoujia {  
            manifestPlaceholders = [ CHANNEL_NAME:"WANDOUJIA" ]  
        }  

    }  
    // 你的其他配置程式碼  
}  

在上面當中,我們也可以指定一個預設的渠道名,如果需要的話。指定預設的值是在defaultConfig節點當中新增如下內容:

manifestPlaceholders = [ CHANNEL_NAME:"Unspecified"]  

這裡的Unspecified換成你實際上的預設的渠道名。

使用manifestPlaceholders的這種配置,同樣適用於manifest的其他配置。比如你需要在不同渠道釋出的apk裡面,指定不同的啟動Activity。比如在豌豆莢裡面釋出的,啟動的Activity顯示的是豌豆莢首發的介面,應用寶裡面啟動的是應用寶首發的介面(哈哈,有點壞),你就可以對你的activity的值使用①的方式,然後在productFlavors裡面配置這個①的值。

①:${activity_name}