Android Gradle必備基礎知識

隨着GoogleEclipse的無情拋棄以及Studio的不斷壯大,Android開發者逐漸拜倒在Studio的石榴裙下。
而做爲Studio的默認編譯方式,Gradle已逐漸普及。我最開始是被它的多渠道打包所吸引。接下來咱們就係統的學習一下Gradlejava

簡介

Gradle是以Groovy語言爲基礎,面向Java應用爲主。基於DSL(Domain Specific Language)語法的自動化構建工具。android

Gradle集合了Ant的靈活性和強大功能,同時也集合了Maven的依賴管理和約定,從而創造了一個更有效的構建方式。憑藉GroovyDSL和創新打包方式,Gradle提供了一個可聲明的方式,並在合理默認值的基礎上描述全部類型的構建。 Gradle目前已被選做許多開源項目的構建系統。git

由於Gradle是基於DSL語法的,若是想看到build.gradle文件中所有能夠選項的配置,能夠看這裏
DSL Referencegithub

基本的項目設置

一個Gradle項目經過一個在項目根目錄中的build.gradle文件來描述它的構建。app

簡單的Build文件

最簡單的Android應用中的build.gradle都會包含如下幾個配置:
Project根目錄的build.gradle:ide

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

Module中的build.gradle:工具

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    ...
}
  • buildscript { ... }配置了編譯時的代碼驅動. 這種狀況下,它聲明所使用的是jCenter倉庫。還有一個聲明所依賴的在Maven文件的路徑。這裏聲明的包含了Android插件所使用的1.5.0版本的Gradle. 注意:這隻會影響build中運行的代碼,不是項目中。項目中須要聲明它本身所須要倉庫和依賴關係。
  • apply plugin : com.android.application,聲明使用com.androdi.application插件。這是構建Android應用所須要的插件。
  • android{...}配置了全部Android構建時的參數。默認狀況下,只有編譯的目標版本以及編譯工具的版本是須要的。

重要: 這裏只能使用com.android.application插件。若是使用java插件將會報錯。學習

目錄結構

module/src/main下的目錄結構,由於有時候不少人把so放到libs目錄就會報錯:gradle

  • java/
  • res/
  • AndroidManifest.xml
  • assets/
  • aidl/
  • jniLibs/
  • jni/
  • rs/

配置目錄結構

若是項目的結構不標準的時候,可能就須要去配置它。Android插件使用了類似的語法,可是由於它有本身的sourceSets,因此要在android代碼塊中進行配置。下面就是一個從Eclipse的老項目結構中配置主要代碼而且將androidTestsourceSet設置給tests目錄的例子:ui

android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        androidTest.setRoot('tests')
    }
}

就像有些人就是要把so放到libs目錄中(這類人有點犟),那就須要這樣進行修改。
注意:由於在舊的項目結構中全部的源文件(Java,AIDLRenderScript)都放到同一個目錄中,咱們須要將sourceSet中的這些新部件都設置給src目錄。

Build Tasks

對構建文件聲明插件時一般或自動建立一些列的構建任務去執行。無論Java插件仍是Android插件都是這樣。Android常規的任務以下:

  • assemble生成項目output目錄中的內容的任務。
  • check執行全部的檢查的任務。
  • build執行assemblecheck的任務。
  • clean清理項目output目錄的任務。

Android項目中至少會有兩種output輸出:一個debug apk和一個release apk。他們都有本身的主任務來分別執行構建:

  • assemble

    • assembleDebug
    • assembleRelease

提示:Gradle支持經過命令行執行任務首字母縮寫的方式。例如:
在沒有其餘任務符合aR的前提下,gradle aRgradle assembleRelease是相同的。

最後,構建插件建立了爲全部build type(debug, release, test)類型安裝和卸載的任務,只要他們能被安裝(須要簽名)。

  • installDebug
  • installRelease
  • uninstallAll

    • uninstallDebug
    • uninstallRelease
    • uninstallDebugAndroidTest

基本的Build定製

Android插件提供了一些列的DSL來讓直接從構建系統中作大部分的定製。

Manifest總體部分

DSL提供了不少重要的配置manifest文件的參數,例如:

  • minSdkVersion
  • targetSdkVersion
  • versionCode
  • versionName
  • applicationId
  • testApplicationId
  • testInstrumentationRunnder

Android Plugin DSL Reference提供了一個完整的構建參數列表。

把這些manifest屬性放到build文件中的一個重要功能就是它能夠被動態的設置。例如,能夠經過讀取一個文件或者其餘邏輯來獲取版本名稱。

def computeVersionName() {
    ...
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"


    defaultConfig {
        versionCode 12 
        versionName computeVersionName()
        minSdkVersion 16
        targetSdkVersion 23
    }
}

注意:不要使用可能與現有給定衝突的方法名。例如defaultConfig{...}中使用getVersionName()方法將會自動使用defaultConfig.getVersionName()來帶起自定義的方法。

Build Types

默認狀況下Android插件會自動將應用程序設置成有一個debug版本和一個release版本。
這就是經過調用BuildType對象完成。默認狀況下會建立兩個實例,一個debug實例和一個release實例。Android插件一樣容許經過其餘的Build Types來定製其餘的實例。這就是經過buildTypes來設置的:

android {
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }


        jnidebug {
            initWith(buildTypes.debug)
            applicationIdSuffix ".jnidebug"
            jniDebuggable true
        }
    }
}

上面的代碼執行了如下操做:

  • 配置了默認debugBuild Type:

    • 設置了它的applicationId。這樣debug模式就能與release模式的apk同時安裝在同一手機上。
  • 建立了一個新的jnidebugBuild Type,而且把它設置爲debug的拷貝。
  • 經過容許JNI組件的debug和增長一個新的包名後綴來繼續定製該Build Type

無論使用initWith()仍是使用其餘的代碼塊,建立一個新的Build Types都是很是簡單的在buildTypes代碼塊中建立一個新的元素就能夠了。

簽名配置

爲應用簽名須要使用以下幾個部分:

  • A keystore
  • A keystore password
  • A key alias name
  • A key password
  • The store type

默認狀況下有一個debug的配置,設置了一個debugkeystore,有一個已知的密碼。debug keystore的位置是在$HOME/.android/debug.keystore,若是沒有的話他會被默認建立。DebugBuild Type會默認使用該debug的簽名設置。

固然也能夠經過使用DSL語法中的signingconfigs部分來建立其餘的配置來進行定製:

android {
    signingConfigs {
        debug {
            storeFile file("debug.keystore")
        }


        myConfig {
            storeFile file("other.keystore")
            storePassword "android"
            keyAlias "androiddebugkey"
            keyPassword "android"
        }
    }


    buildTypes {
        foo {
            signingConfig signingConfigs.myConfig
        }
    }
}

上面的設置將把debug keystore的位置改成項目的根目錄。一樣也建立了一個新的簽名配置,而且有一個新的Build Type使用它。

Dependencies, Android Libraries and Multi-project setup

Gradle項目能夠依賴其餘的外部二進制包、或者其餘的Gradle項目。

本地包

想要配置依賴一個外部jar包,須要在compile的配置中添加一個dependency。下面的配置是添加了全部在libs目錄的jar包:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}


android {
    ...
}

注意:DSL元素中的dependenciesGradle API中的標準元素。不屬於andorid元素。
compile配置是用來編譯主應用的。它配置的全部部分都會被打包到apk中。固然也有一些其餘的配置:

  • compile: main application
  • androidTestCompile:test application
  • debugCompile:debug Build Type
  • release Compile:release Build Type

固然咱們可使用compile<buildtype>.compile這兩種配置。建立一個新的Build Type一般會自動基於它的名字建立一個新的配置部分。這樣在像debug版本而release版本不適用的一些特別的library時很是有用。

遠程倉庫

Gradle只是使用MavenIvy倉庫。可是倉庫必需要添加到列表中,而且必須聲明所依賴倉庫的Maven或者Ivy定義。

repositories {
     jcenter()
}


dependencies {
    compile 'com.google.guava:guava:18.0'
}


android {
    ...
}

注意:jcenter()是指定倉庫URL的快捷設置。Gradle支持遠程和本地倉庫。
注意:Gradle會直接識別全部的依賴關係。這就意味着若是一個依賴庫自身又依賴別的庫時,他們會被一塊兒下下來。

本地AAR
dependencies {
    compile(name:'本地aar庫的名字,不用加後綴', ext:'aar')
}
多項目設置

Gradle項目一般使用多項目設置來依賴其餘的gradle項目。例如:

  • MyProject/

    • app/
    • libraries/

      • lib1/
      • lib2/

Gradle會經過下面的名字來引用他們:
:app
:libraries:lib1
:libraries:lib2

每一個項目都會有一個單獨的build文件,而且在項目的根目錄還會有一個setting.gradle文件:

  • MyProject/

    • settings.gradle
    • app/

      • build.gradle
    • libraries/

      • lib1/

        • build.gradle
      • lib2/

        • build.gradle

setting.gradle文件中的內容很是簡單。它指定了哪一個目錄是Gralde項目:

include ':app', ':libraries:lib1', ':libraries:lib2'

:app這個項目可能會依賴其餘的libraries,這樣能夠經過以下進行聲明:

dependencies {
     compile project(':libraries:lib1')
}

Library項目

上面用到了:libraries:lib1:libraries:lib2能夠是Java項目,:app項目會使用他們倆的輸出的jar包。可是若是你須要使用android資源等,這些libraries就不能是普通的Java項目了,他們必須是Android Library項目。

建立一個Library項目

Library項目和普通的Android項目的區別比較少,因爲libraries的構建類型與應用程序的構建不一樣,全部它會使用一個別的構建插件。可是他們所使用的插件內部有不少相同的代碼,他們都是由com.android.tools.build.gradle這個jar包提供的。

buildscript {
    repositories {
        jcenter()
    }


    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
    }
}


apply plugin: 'com.android.library'


android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"
}
普通項目與Library項目的區別

Library項目的主要輸出我.aar包。它結合了代碼(例如jar包或者本地.so文件)和資源(manifest,res,assets)。每一個library也能夠單獨設置Build Type等來指定生成不一樣版本的aar

Lint Support

你能夠經過指定對應的變量來設置lint的運行。能夠經過添加lintOptions來進行配置:

android {
    lintOptions {
        // turn off checking the given issue id's
        disable 'TypographyFractions','TypographyQuotes'

        // turn on the given issue id's
        enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'

        // check *only* the given issue id's
        check 'NewApi', 'InlinedApi'
    }
}

Build變量

構建系統的一個目標就是能對同一個應用建立多個不一樣的版本。

Product flavors

一個product flavor能夠針對一個項目制定不一樣的構建版本。一個應用能夠有多個不一樣的falvors來改變生成的應用。
Product flavors是經過DSL語法中的productFlavors來聲明的:

android {
    ....


    productFlavors {
        flavor1 {
            ...
        }


        flavor2 {
            ...
        }
    }
}
Build Type + Product Flavor = Build Variant

像咱們以前看到的,每一個Build Type都會生成一個apk.Product Flavors也是一樣的:項目的輸出殭屍全部Build TypesProduct Flavors的結合。每種結合方式稱之爲Build Variant。例如,若是有debugrelease版本的Build Types,上面的例子就會生成4種Build Variants

  • Flavor1 - debug
  • Flavor1 - release
  • Flavor2 - debug
  • Flavor2 - release

沒有配置flavors的項目仍然有Build Variants,它只是用了一個默認的flavor/config,沒有名字,這致使variants的列表和Build Types的列表比較相同。

Product Flavor配置
android {
    ...


    defaultConfig {
        minSdkVersion 8
        versionCode 10
    }


    productFlavors {
        flavor1 {
            applicationId "com.example.flavor1"
            versionCode 20
         }


         flavor2 {
             applicationId "com.example.flavor2"
             minSdkVersion 14
         }
    }
}

注意android.productFlavors.*對象ProductFlavorandroid.defaultConfig是相同的類型。這就意味着他們有相同的屬性。
defaultConfig爲全部的flavors提供了一些基本的配置,每一個flavor都已重寫他們。在上面的例子中,這些配置有:

  • flavor1

    • applicationId: com.example.flavor1
    • minSdkVersion: 8
    • versionCode: 20
  • flavor2

    • applicationId: com.example.flavor2
    • minSdkVersion: 14
    • versionCode: 10

一般,Build Type配置會覆蓋其餘的配置。例如,Build TypeapplicationIdSuffix會添加到Product FlavorapplicationId上。

最後,就像Build Types同樣,Product Flavors也能夠有他們本身的依賴關係。例如,若是有一個單獨的flavors會使用一些廣告或者支付,那這個flavors生成的apk就會使用廣告的依賴,而其餘的flavors就不須要使用。

dependencies {
    flavor1Compile "..."
}

BuildConfig

在編譯階段,Android Studio會生成一個叫作BuildConfig的類,該類包含了編譯時使用的一些變量的值。你能夠觀看這些值來改變不一樣變量的行爲:

private void javaCode() {
    if (BuildConfig.FLAVOR.equals("paidapp")) {
        doIt();
    else {
        showOnlyInPaidAppDialog();
    }
}

下面是BuildConfig中包含的一些值:

  • boolean DEBUG - if the build is debuggable
  • int VERSION_CODE
  • String VERSION_NAME
  • String APPLICATION_ID
  • String BUILD_TYPE- Build Type的名字,例如release
  • String FLAVOR - flavor的名字,例如flavor1

ProGuard配置

Android插件默認會使用ProGuard插件,而且若是Build Type中使用ProGuardminifyEnabled屬性開啓的話,會默認建立對應的task

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFile getDefaultProguardFile('proguard-android.txt')
        }
    }

    productFlavors {
        flavor1 {
        }
        flavor2 {
            proguardFile 'some-other-rules.txt'
        }
    }
}

Tasks控制

基本的Java項目有一系列的tasks一塊兒製做輸出文件。
classes task就是編譯Java源碼的任務。 咱們能夠在build.gradle中經過使用classes很簡單的獲取到它。就是project.tasks.classes.

Android項目中,更多的編譯task,由於他們的名字經過Build TypesProduct Flavors生成。

爲了解決這個問題,android對象有兩種屬性:

  • applicationVariants - only for the app plugin
  • libraryVariants - only for the library plugin
  • testVariants - for both plugins
    這些都會返回一個ApplicationVariant, LibraryVariant,TestVariantDomainObjectCollection接口的實現類對象。
    DomainObjectCollection提供了直接獲取或者很方便的間接獲取全部對象的方法。

    android.applicationVariants.all { variant ->
     ....
    }

設置編譯語言版本

可使用compileOptions代碼塊來設置編譯時使用的語言版本。默認是基於compileSdkVersion的值。

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_6
        targetCompatibility JavaVersion.VERSION_1_6
    }
}

Resource Shrinking

Gradle構建系統支持資源清理:對構建的應用會自動移除無用的資源。不只會移除項目中未使用的資源,並且還會移除項目因此來的類庫中的資源。注意,資源清理只能在與代碼清理結合使用(例如ProGuad)。這就是爲何它能移除所依賴類庫的無用資源。一般,類庫中的全部資源都是使用的,只有類庫中無用代碼被移除後這些資源纔會變成沒有代碼引用的無用資源。

android {
    ...

    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
相關文章
相關標籤/搜索