随着GoogleEclipse的有情摈弃以及Studio的一直壮大,Android开发者逐步拜倒在Studio的石榴裙下。
而作为Studio的默认编译形式,Gradle已逐步遍及。我最开始是被它的多渠道打包所吸引。接下来咱们就零碎的学习一下Gradle

简介

Gradle是以Groovy语言为根底,面向Java利用为主。基于DSL(Domain Specific Language)语法的自动化构建工具。

Gradle汇合了Ant的灵活性和弱小性能,同时也汇合了Maven的依赖治理和约定,从而发明了一个更无效的构建形式。凭借GroovyDSL和翻新打包形式,Gradle提供了一个可申明的形式,并在正当默认值的根底上形容所有类型的构建。 Gradle目前已被选作许多开源我的项目的构建零碎。

因为Gradle是基于DSL语法的,如果想看到build.gradle文件中全副能够选项的配置,能够看这里
DSL Reference

根本的我的项目设置

一个Gradle我的项目通过一个在我的项目根目录中的build.gradle文件来形容它的构建。

简略的Build文件

最简略的Android利用中的build.gradle都会蕴含以下几个配置:
Project根目录的build.gradle:

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目录就会报错:

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

配置目录构造

如果我的项目的构造不规范的时候,可能就须要去配置它。Android插件应用了类似的语法,然而因为它有本人的sourceSets,所以要在android代码块中进行配置。上面就是一个从Eclipse的老我的项目构造中配置次要代码并且将androidTestsourceSet设置给tests目录的例子:

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'        }    }}