Gradle的基本使用

Gradle的介紹

Gradle是一個基於Apache Ant和Apache Maven概念的項目自動化建構工具。它使用一種基於Groovy的特定領域語言(DSL)來聲明項目設置,拋棄了基於XML的各類繁瑣配置。html

面向Java應用爲主。當前其支持的語言限於Java、Groovy和Scala,計劃將來將支持更多的語言。java

Gradle入門知識

projects 和 tasks是Gradle中最重要的兩個概念,任何一個Gradle構建都是由一個或者多個project組成,每一個project能夠是一個jar包,一個web應用,或者一個Android app等,每一個project又由多個task構成,一個task其實就是構建過程當中一個原子性的操做,好比編譯、拷貝等。linux

一個build.gradle文件是一個構建腳本,當運行gradle命令的時候會從當前目錄查找build.gradle文件來執行構建。下面咱們來看下gradle的Hello World。在build.gradle構建文件中輸入如下構建腳本:android

task hello {
    doLast {
        println 'Hello world!'
    }
}
  •  

task定義了一個任務,這個任務名字是hello。doLast是Task的方法,意思是在該hello任務執行以後做的事情,能夠用一個閉包配置它,這裏是輸出Hello world!字符串。咱們在終端裏執行以下命令運行查看結果:git

$gradle hello -q
Hello world!
  • 1
  • 2
  • 1
  • 2

Android Studio的結構

這裏新建一個android項目,選擇Project結構模式,下面是項目的結構示意圖web

├── ApplicationName #項目路徑
│   ├── .gradle
│   ├── .idea
│   ├── app #Android App目錄
│   │   ├── build #構建輸出目錄
│   │   ├── libs#so相關庫
│   │   ├── src #源代碼,資源等
│   │   └── .gitignore  
│   │   └── app.im
│   │   └── buidle.gradle#構建腳本
│   │   └── proguard-rules.pro#proguard混淆配置
│   ├── build
│   │   ├── intermediates
│   ├── gradle  
│   │   ├── wrapper
│   └── .gitignore  
│   └── buidle.gradle #工程構建文件
│   └── gradle.properties#gradle的配置
│   └── gradlew #gradle wrapper linux shell腳本
│   └── gradlew.bat
│   └── local.properties #配置Androod SDK位置文件
│   └── MyApplication.iml
│   └── settings.gradle #工程配置
├── External Liraies#類庫、jar等

settings.gradle用於配置project,標明其下有幾個module,好比這裏p一個:ape 
moduleshell

include ':app'
  • 1
  • 1

build.gradle(Project:projectName)是一個頂級的build配置文件,在這裏能夠爲全部project以及module配置一些經常使用的配置。服務器

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
    //使用jcenter庫
        jcenter()
    }
    dependencies {   
        // 依賴android提供的1.3.0的gradle build
        classpath 'com.android.tools.build:gradle:1.3.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
//爲全部的工程的repositories配置爲jcenter
allprojects {
    repositories {
        jcenter()
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}
  •  

build.gradle(Module:moduleName)用於module的配置,也是最重要的部分閉包

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.example.zqw.myapplication"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.0'
    compile 'com.android.support:design:23.1.0'
}
  • 1
  • apply plugin: ‘com.android.application’:表示該module是一個app module,應用了com.android.application插件,若是是一個android library,那麼這裏的是apply plugin: ‘com.android.library’。
  • compileSdkVersion :是你SDK的版本號,也就是API Level,例如API-1九、API-20、API-21等等
  • buildToolsVersion 「23.0.2」:是你構建工具的版本,其中包括了打包工具aapt、dx等等。這個工具的目錄位於..your_sdk_path/build-tools/XX.XX.XX這個版本號通常是API-LEVEL.0.0。 例如I/O2014大會上發佈了API20對應的build-tool的版本就是20.0.0在這之間可能有小版本,例如20.0.1等等。
  • defaultConfig:是默認配置,若是沒有其餘的配置覆蓋,就會使用這裏的。看其屬性的名字就能夠知道其做用,好比applicationId是配置包名的,versionCode是版本號,versionName是版本名稱等。
  • buildTypes是構建類型,經常使用的有release和debug兩種,能夠在這裏面啓用混淆,啓用zipAlign以及配置簽名信息等。
  • dependencies不屬於Android專有的配置了,它定義了該module須要依賴的jar,aar,jcenter庫信息。

Gradle配置簽名

Gradle 配置應用的簽名信息

這些配置放在上面提到的build.gradle(Module:moduleName)裏面app

signingConfigs {//簽名配置這裏配置了release 對應的還能夠有debug
    release {
        storeFile file("keystore.jks")//這個文件須要放在modele所在根目錄下
        keyAlias "testapp"
        keyPassword "111111"
        storePassword "111111"
    }
}
buildTypes {
    release {
        signingConfig  signingConfigs.release//不要忘了要在release的時候加入我麼的簽名配置信息
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

使用Gradle簽名

第一種方式是使用Gradle工具,雙擊下圖選擇的命令便可,在控制檯看到BUILD SUCCESSFUL就代表簽名成功了,由於咱們沒有配置文件的生成路徑因此會在默認地址裏面C:\project\demo\MyApplication\app\build\outputs\apk 
這裏寫圖片描述 
第二種方式使用命令。打開Terminal選項卡,用最下方標籤切換。打開以後咱們先敲一下gradle –help命令驗證一下是否能夠執行gradle命令。若是不能夠的話,在環境變量裏邊配置一下gradle的path。

gradle assembleRelease

Gradle配置proguard混淆

咱們能夠爲不一樣的buildTypes選擇是否啓用混淆,通常release發佈版本是須要啓用混淆的,這樣別人反編譯以後就很難分析你的代碼,而咱們本身開發調試的時候是不須要混淆的,因此debug不啓用混淆。對release啓用混淆的配置以下:

android {

    buildTypes {
        release {
            minifyEnabled true
            proguardFile 'proguard.cfg'
        }
   }
}
  •  

minifyEnabled爲true表示啓用混淆,proguardFile是混淆使用的配置文件,這裏是module根目錄下的proguard.cfg文件

在上面咱們配置簽名信息採用的是默認寫法。下面是對默認寫法的解釋 
proguard-android.txt是sdk中groguard默認的文件,具體地址在:/opt/sdk/tools/proguard/proguard-android.txt 
proguard-rules.pro是AS中專用的proguard配置文件,其實只是後綴名不一樣,與Eclipse中的proguard-project.txt是同樣的,配置規則相同 
老版本開啓混淆的命令是runProguard,如今統一用minifyEnabled命令了,將其設爲true就行了。

Gradle啓用zipAlign

zipalign是Android SDK中包含一個的工具,它可以對打包的應用程序進行優化。在你的應用程序上運行zipalign,使得在運行時Android與應用程序間的交互更加有效率。所以,這種方式可以讓應用程序和整個系統運行得更快。強烈推薦在新的和已經發布的程序上使用zipalign工具來獲得優化後的版本——即便你的程序是在老版本的Android平臺下開發的。

在Android中,每一個應用程序中儲存的數據文件都會被多個進程訪問:安裝程序會讀取應用程序的manifest文件來處理與之相關的權限問題;Home應用程序會讀取資源文件來獲取應用程序的名和圖標;系統服務會由於不少種緣由讀取資源(例如,顯示應用程序的Notification);此外,就是應用程序自身用到資源文件。

在Android中,當資源文件經過內存映射對齊到4字節邊界時,訪問資源文件的代碼纔是有效率的。可是,若是資源自己沒有進行對齊處理(未使用zipalign工具),它就必須回到老路上,顯式地讀取它們——這個過程將會比較緩慢且會花費額外的內存。

對於應用程序開發者來講,這種顯式讀取方式是至關便利的。它容許使用一些不一樣的開發方法,包括正常流程中不包含對齊的資源,所以,這種讀取方式具備很大的便利性(本段的原始意思請參考原文)。

遺憾的是,對於用戶來講,這個狀況偏偏是相反的——從未對齊的apk中讀取資源比較慢且花費較多內存。最好的狀況是,Home程序和未對齊的程序啓動得比對齊後的慢(這也是惟一可見的效果)。最壞的狀況是,安裝一些未對齊資源的應用程序會增長內存壓力,並所以形成系統反覆地啓動和殺死進程。最終,用戶放棄使用如此慢又耗電的設備。

開啓zipAlign配置以下

android {

    buildTypes {
        release {
            zipAlignEnabled true
        }
   }
}
  •  

Gradle刪除無用資源

在項目屢次版本迭代後有一部分資源文件可能不在使用了,若是之前負責的人離開或者不在負責這個了,那麼後面接收的人就不敢刪除,這樣安裝包就會愈來愈大,之前使用工具能夠找到沒被使用的資源。如今android gradle也直接支持,配置以下

android {

    buildTypes {
        release {
          shrinkResources true 
        }
   }
}
  •  

多渠道打包

多渠道這個也是android平臺特有的,由於有360手機助手、應用寶、小米應用市場等等大量相似AppStore的應用商城。在項目發佈之後須要對後臺數據分渠道統計,因此纔有了多渠道打包。Android Gradle給咱們提供了productFlavors,讓咱們能夠對生成的APK包進行定製

android  {
    productFlavors {
        dev{

        }
        google{

        }
        baidu{

        }
    }
}
  •  

這樣當咱們運行assembleRelease的時候就會生成3個release包,分別是dev、google以及baidu的。目前看這三個包除了文件名沒有什麼不同,由於咱們尚未定製,使用的都是defaultConfig配置。這裏的flavor和defaultConfig是同樣的,能夠自定義其applicationId、versionCode以及versionName等信息,好比區分不一樣包名:注意實際發佈項目APP的報名應該是惟一的,這裏這是爲了說明能夠改

android  {
    productFlavors {
        dev{
            applicationId "org.flysnow.demo.dev"
        }
        google{
            applicationId "org.flysnow.demo.google"
        }
        baidu{
            applicationId "org.flysnow.demo.baidu"
        }
    }
}
  • 批量修改生成的apk文件名

在咱們打包發版的時候,一次性打幾十個包,這時候咱們就想讓生成的apk文件名有區分,好比一眼就能看出這個apk是哪一個版本的,哪一個渠道的,是哪天打的包等等,這就須要咱們在生成apk文件的時候動態修改生成的apk文件名達到這一目的。

def buildTime() {
    def date = new Date()
    def formattedDate = date.format('yyyyMMdd')
    return formattedDate
}

android {
    buildTypes {
        release {
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    if (output.outputFile != null && output.outputFile.name.endsWith('.apk')
                        &&'release'.equals(variant.buildType.name)) {
                        def apkFile = new File(
                                output.outputFile.getParent(),
                                "testapp_${variant.flavorName}_v${variant.versionName}_${buildTime()}.apk")
                        output.outputFile = apkFile
                    }
                }
            }
        }
    }
}
  •  

以baidu渠道爲例,以上的代碼會生成一個名字爲testapp_baidu_v9.5.2.6_20150330.apk安裝包。下面咱們分析一下,Android Gradle任務比較複雜,它的不少任務都是自動生成的,爲了能夠更靈活的控制,Android Gradle提供了applicationVariants、libraryVariants以及testVariants,他們分別適用於app、library、app和library都適用。

這裏是循環處理每一個applicationVariant,當他們的輸出文件名以apk結尾而且buildType是release時,從新設置新的輸出文件名,這樣就達到了咱們批量修改生成的文件名的目的。

Gradle使用AndroidManifest裏的佔位符

這裏用到的佔位符也是讓動態打包的APK包內配置信息和渠道對於,用於第三方的統計分析,以友盟統計爲例

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

若是是單一渠道咱們能夠直接給value賦值好比value=「baidu」,這樣在項目代碼中去獲取UMENG_CHANNEL值就知道是哪個渠道了,由於打的渠道包很是的多因此咱們能夠採用上面佔位符方式 
下面是gradle的配置

android {
    defaultConfig {
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: 'dev']
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

咱們的默認配置裏AndroidManifest的${UMENG_CHANNEL_VALUE}佔位符會被dev這個字符串所替換,也就說默認運行的版本是一個開發板。以此類推,咱們其餘渠道的版本就能夠這樣定義:

android  {
    productFlavors {
        google{
            applicationId "org.flysnow.demo.google"
            manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'google')
        }
        baidu{
            applicationId "org.flysnow.demo.baidu"
            manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'baidu')
        }
    }
}
  •  

這樣寫依然過於繁瑣,咱們能夠直接用渠道名稱來給這個佔位符賦值

productFlavors.all { flavor ->
        manifestPlaceholders.put("UMENG_CHANNEL_VALUE",name)
    }
  •  

自定義你的BuildConfig

在咱們實際項目開發中通常會有測試環境和正式環境的區分(和服務器有交互的APP),通常咱們會寫一個配置文件,根據不一樣狀況來訪問不一樣的環境。之前的時候咱們經過把不一樣的配置文件打包進APK中來控制,Android Gradle能夠動態生成BuildConfig.java,咱們只須要填寫信息便可,使用起來更加方便。

android {
    defaultConfig {
        buildConfigField 'String','API_SERVER_URL','"http://www.myweb.com/"'
    }
    productFlavors {
        google{
            buildConfigField 'String','API_SERVER_URL','"http://www.google.com/"'
        }
        baidu{
            buildConfigField 'String','API_SERVER_URL','"http://www.baidu.com/"'
        }
    }
}
  •  

buildConfigField 一共有3個參數,第一個是數據類型,就是你定義的常量值是一個什麼類型,和Java的類型是對等的,這裏是String。第二個參數是常量名,這裏是API_SERVER_URL。第三個參數是常量值。如此定義以後,就會在BuildConfig.java中生成一個常量名爲API_SERVER_URL的常量定義。默認配置的生成是:

public final static String API_SERVER_URL = "http://www.myweb.com/"

當是baidu和google渠道的時候生成的就是http://www.myweb.com/了。這個常量能夠在咱們編碼中引用。在咱們進行打包的時候會根據Gradle配置動態替換。

咱們發現通常渠道版本都是用來發布的,確定用的是生產服務器,因此咱們可使用批處理來搞定這個事情,而不用在一個個渠道里寫這些配置。

productFlavors.all { flavor ->
    buildConfigField 'String','API_SERVER_URL','"http://www.flysnow.org/"'
}

此外,好比Gradle的resValue,也是和buildConfigField,只不過它控制生成的是資源,好比咱們在android的values.xml定義生成的字符串。能夠用它來動態生成咱們想要的字符串,好比應用的名字,可能一些渠道會不同,這樣就能夠很靈活的控制自動生成,關於resValue詳細介紹請參考相關文檔,這裏再也不舉例說明。

插裝測試覆蓋率代碼

dexOptions javaMaxHeapSize

在Gradle 進行dex的可能會遇到內

源碼地址

部份內容來源1 部份內容來源2

相關文章
相關標籤/搜索