Android Gradle插件用户指南(译)

Android Gradle插件用户指南(译)

原文Gradle Plugin User Guide - Android Tools Project Site 
samples see bottom of New Build System 
参考Gradle For Android Training Coursehtml

1 简介

这篇文档是基于0.9版本的Gradle插件,1.0之前的版本因为不兼容,可能会有所不一样java

1.1 新的构建系统的目标

新构建系统的目标是:android

  • 使得代码和资源的重用更加简单
  • 使得建立同一应用程序的不一样版本更加容易,无论是多个apk版本仍是同一版本的多种定制
  • 使得配置,扩展和自定义构建更加容易
  • 良好的IDE集成

1.2 为何使用Gradle

Gradle是一个高级构建系统和构建工具,容许经过插件自定义构建逻辑git

如下一些功能使得咱们选择Gradle:api

  • 使用特定领域语言(DSL)来描述和控制构建逻辑
  • 构建脚本基于Groovy语言,容许经过DSL混合元素声明和经过代码控制DSL元素,来产生自定义的构建逻辑
  • 支持Maven和(或者)Ivy管理依赖
  • 很是灵活。容许使用最佳实践,但也不强制本身的实现方式
  • 插件可以提供本身的DSL和API供构建脚本使用
  • 提供优秀的工具API以供IDE集成

2 环境要求

  • Gradle 1.10或者1.11或者1.12,以及插件版本0.11.1
  • SDK以及Buid Tools 19.0.0,某些功能可能须要更新的版本

3 基本项目

Gradle项目经过项目根目录下的 build.gradle 文件来描述构建过程数组

3.1 简单的构建文件

最简单的Java项目构建文件 build.gradle安全

apply plugin: 'java'
  • 1

这个脚本应用了Gradle的Java插件。这个插件了提供构建和测试Java应用的全部功能服务器

最简单的Android项目的构建文件包含如下内容: 网络

buildscript {
    repositories {
        mavenCentral()
    }

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

apply plugin: 'android'

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"
}

Note(译注): 最新的android插件声明 
apply plugin: 'com.android.application'闭包

在这个Android构建脚本里包含了三个主要内容:

buildscript { ... } 配置了驱动构建过程的代码。在这个案例中,声明了使用Maven仓库,以及一个Maven文件(artifact)的依赖路径。这个文件就是包含了Android Gradle插件的库,版本为0.11.1

而后,android插件被应用,像以前的Java插件同样

最后,android { ... } 配置了anroid构建过程须要的参数。这也是Adnroid DSL的入口。默认的状况下,只有编译目标SDK版本,和构建工具版本是必须的。在脚本中,对应的是compileSdkVersionbuildtoolsVersion属性。compileSdkVersion和旧编译系统中project.properties文件中的target属性对应。这个新属性compileSdkVersion能够是一个int值(API Level)或者一个和以前的target属性值同样的字符串

重点: 你应该只应用android插件,同时应用java插件会致使构建错误

注意: 你一样须要一个local.properties文件来指明SDK的路径,和build.gradle在同一路径下,在文件中使用sdk.dir属性指明。或者,你能够设置ANDROID_HOME环境变量。二者是一致的,你能够选择一种你喜欢的方式。

3.2 项目结构

前面的android构建脚本使用了默认的文件夹目录结构。Gradle遵循约定优于配置的原则,在可能的状况下提供了合理的默认配置参数。

基本的项目包含两个“source sets”组件。main source codetest code,位于如下的目录中:

src/main/
src/androidTest/
  • 1
  • 2

在这些目录中,都存在目录对应源码组件

无论是Java仍是Android插件,源码目录和资源目录都以下 :

java/
resources/
  • 1
  • 2

对于Android插件,还有特有的文件和目录

AndroidManifest.xml
res/
assets/
aidl/
rs/
jni/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Note: src/androidTest/AndroidManifest.xml 不是必须的,会自动被建立。

3.2.1 配置项目结构

当默认项目结构不合适的时候,能够配置项目目录。根据Gradle文档,能够经过下面的脚本从新配置Java项目的sourceSets:

sourceSets {
    main {
        java {
            srcDir 'src/java'
        }
        resources {
            srcDir 'src/resources'
        }
    }
}

Note: srcDir 会添加指定的目录到源文件目录列表中(这在Gradele文档中没有说起,可是其实是这样的)。

为了替换默认的源文件目录列表,可使用srcDirs来指定目录数组。这也是一种不一样的使用方式:

sourceSets {
    main.java.srcDirs = ['src/java']
    main.resources.srcDirs = ['src/resources']
}

更多的信息,参考Gradle文档中的Java插件内容

Android插件使用类似的语法,可是因为使用是本身的sourceSets,相应的目录在(build.gradle文件中的)android对象中指定

下面是一个示例,它使用旧项目的源码结构,而且将androidTest sourceSet映射到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')
    }
}

Note: 因为旧的结构将全部的源文件 (java, aidl, renderscript, and java资源文件)放在一个目录里,咱们须要映射这些sourceSet组件到src目录。

Note: setRoot() 方法将整个sourceSet(包含子目录)指向新的目录。好比上面,将src/androidTest/* 指向了 tests/*

以上是Android特有的,若是配置在Java sourceSets中就没有做用

‘migrated’ 示例(位于本页面底部)中展现了这部份内容

3.3 构建任务

3.3.1 通用任务

在build文件中应用一个插件将自动建立一系列构建任务。Java插件和Android插件都是这样。任务约定以下:

  • assemble

组合项目输出

  • check

执行全部检查

  • build

执行assemble和check两个task的全部工做

  • clean 

清理项目输出

任务assemblecheck 和 build 不会作任何实际的事情。他们只是锚点任务(anchor tasks),插件依赖他们来添加实际执行实际操做的任务。

这样就不须要考虑项目是什么类型,使用的是什么插件,均可以执行一样的任务。 
例如,使用findbugs插件,会建立新的任务,并让check依赖这个任务,使得check被调用时这个任务就会被调用。

在终端(命令行,gradle项目目录下)中运行下面的任务能够查询到高级别的任务:

gradle tasks
  • 1

运行如下命令能够看到所有任务和任务依赖关系:

gradle tasks --all
  • 1

Note: Gradle自动监视一个任务声明的输入输出文件。再次执行构建任务时,若是文件没有改变,Gradle会指明全部任务为UP-TO-DATE,意味着任务不须要执行。这样的话,任务能够正确地互相依赖,而不不会致使非必须的构建操做

3.3.2 Java项目的任务

Java插件主要建立两个任务,下面是这两个锚点任务的依赖关系

  • assemble 
    • jar 
      这个任务建立输出
  • check 
    • test 
      这个任务运行测试

jar任务直接或间接地依赖其余任务:例如classes任务将编译Java源码 
testClasses任务用于编译测试的,可是这个任务不多被调用,由于test任务依赖于它(就像依赖classes任务同样)

一般来讲,你只须要调用assemble或者check任务,而不须要调用其余任务。

你能够在Gradle Java插件文档看到Java插件的所有任务和它们的描述

3.3.3 Android任务

Android插件使用一样的约定来保持和其余插件的兼容,而且添加了额外的锚点任务:

  • assemble 
    这个任务组织项目的输出

  • check 
    这个项目运行全部检查

  • connectedCheck 
    运行检查须要一个已链接的设备或者模拟器。并在全部已链接的设备上异步运行。

  • deviceCheck 
    经过APIs链接远程设备并运行检查。这一般在CI服务器上运行。

  • build 
    运行assemblecheck

  • clean 
    清理项目输出

新的锚点任务是必须的,以保证在不须要设备链接的状况下能运行常规检查。 
须要注意的是,build任务并不依赖deviceCheck或者connectedCheck

一个Android项目至少有两个输出:debug APK 和 release APK。它们每个都有本身的锚点任务来帮助它们完成独立的构建:

  • assemble 
    • assembleDebug
    • assembleRelease

它们都依赖其它任务来完成构建一个apk所须要的多个步骤。assemble任务依赖这两个任务,因此调用assemble会生成两个APK。

Tip: Gradle支持在命令行中使用camel形式的任务名缩写。 
例如: 
gradle aRgradle assembleRelease是同样的,由于没有别的任务名有一样的缩写

锚点任务check也有本身的依赖:

  • check 
    • lint
  • connectedCheck 
    • connectedAndroidTest
    • connectedUiAutomatorTest (not implemented yet)
  • deviceCheck 
    • 依赖于当其它插件实现测试扩展点时所建立的任务。

最终,插件会为全部构建类型(debug, release, test)建立install/uninstall任务,若是输出文件能够安装的话(必须签名)。

3.4 基本的构建过程定制

Android插件提供了大量DSL来直接从构建系统中定制大多数事情。

3.4.1 Manifest属性

经过DSL,能够配置如下manifest属性:

  • minSdkVersion
  • targetSdkVersion
  • versionCode
  • versionName
  • applicationId (实际的packageName – 前往 ApplicationId versus PackageName 查看更多)
  • Package Name for the test application
  • Instrumentation test runner

例如:

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig {
        versionCode 12
        versionName "2.0"
        minSdkVersion 16
        targetSdkVersion 16
    }
}

配置项位于android元素中的defaultConfig元素中。

以前版本的Android Plugin使用packageName来配置manifest文件的packageName属性。从0.11.1版本开始,你应该在build.gradle文件使用applicationId来配置manifest文件的packageName属性。 
这是为了消除Android应用的packageName(做为Android应用的ID)和java包名之间的疑义。

在构建文件中定义的强大之处在于它能够是动态的。 
例如,能够从一个文件中读取版本名称,或者使用自定义的逻辑:

def computeVersionName() {
    ...
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

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

Note: 函数名不要与指定范围内已经存在的getter方法名冲突。例如,在defaultConfig { ...}中调用getVersionName()会自动使用defaultConfig.getVersionName(),而不是你自定义的其它getVersionName()。

若是属性没有经过DSL设置,那么默认的属性值会被使用。下面是默认的属性值列表:

Property Name Default value in DSL object Default value
versionCode -1 value from manifest if present
versionName null value from manifest if present
minSdkVersion -1 value from manifest if present
targetSdkVersion -1 value from manifest if present
applicationId null value from manifest if present
testApplicationId null applicationId + “.test”
testInstrumentationRunner null android.test.InstrumentationTestRunner
signingConfig null null
proguardFile N/A (set only) N/A (set only)
proguardFiles N/A (set only) N/A (set only)

若是你在构建脚本中使用自定义的逻辑读取这些属性,那么第二列的属性就很重要。例如,你可能这样写:

if (android.defaultConfig.testInstrumentationRunner == null) {
    // assign a better default...
}

若是这个值是null,那么在构建过程当中会被第三列的默认值替代,可是DSL元素不会包含这个默认值(第三列的值),因此你查询不到这个值。这是为了防止解析应用的manifest文件,除非真的必要。

3.4.2 构建类型(Build Types)

默认状况下,Android插件会自动设置项目同时构建debug和release版本的应用程序。 
这两个版本的不一样之处主要在于可否在一个安全设备上调试程序,和APK如何签名。

debug版本使用一个自动建立的密钥/证书,并使用已知的name/password来签名(防止构建过程当中出现请求提示)。release版本在构建过程当中没有签名,须要稍后签名。

这些配置经过一个构建类型(BuildTpye)对象来设置。默认状况下,debug和release这两个构建类型都会被建立。

Android插件容许自定义这两个实例,也容许建立其它构建类型。这些都在buildTypes的DSL容器中配置:

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

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

上面的代码片断完成来如下功能:

  • 配置默认的debug构建类型:

    • 将包名设置成<app appliationId>.debug,以便在同一设备上同时安装debug和release版本
  • 建立了一个新的名为jnidebug的构建类型,是debug构建类型的一个副本

  • 配置jnidebug构建类型,容许调试JNI组件,而且添加一个不一样的包名后缀

建立一个新的构建类型就像在buildTypes容器中使用一个新的元素同样简单,能够经过调用initWith()或者使用闭包来配置

如下是可能用到的属性和它们的默认值:

Property name Default values for debug Default values for release / other
debuggable true false
jniDebuggable false false
renderscriptDebuggable false false
renderscriptOptimLevel 3 3
applicationIdSuffix null null
versionNameSuffix null null
signingConfig android.signingConfigs.debug null
zipAlignEnabled false true
minifyEnabled false false
proguardFile N/A (set only) N/A (set only)
proguardFiles N/A (set only) N/A (set only)

除了以上这些属性,Build Types还能够经过源码和资源来影响构建过程。 
每个构建类型都会建立一个匹配的sourceSet,默认的路径为:

src/<buildtypename>/
  • 1

这意味这新的构建类型的名字不能是main或者androidTest(这是插件强制要求的),而构建类型的名称必须是惟一的。

像其它sourceSet同样,构建类型的sourceSet能够从新被定向:

android {
    sourceSets.jnidebug.setRoot('foo/jnidebug')
}

另外,每个Build Type都会建立一个assemble<BuildTypeName>任务。

在前面,assembleDebugassembleRelease已经提到过了,这就是它们的来源。当debug和release构建类型被预建立的时候,它们相关的任务就被自动建立了,好比assembleDebugassembleRelease

上面的build.gradle片断一样会建立assembleJnidebug任务,assemble会像依赖assembleDebugassembleRelease任务同样依赖assembleJnidebug

Tip: 你能够在命令行下输入gradle aJ来运行assembleJnidebug任务。

可能用到的场景: 

  • 只有debug模式才须要的权限,而release模式不须要
  • 自定义debug实现
  • debug模式使用不一样的资源(例如,资源取值与签名证书绑定)

BuildType的源码和资源经过如下方式使用:

  • manifest文件合并到app的manifest文件中 
  • 源码做为另外一个源码目录
  • 资源叠加到main的资源中,取代已经存在的值

3.4.3 签名配置

对一个应用程序签名须要如下:

  • 一个keystore
  • 一个keystore密码
  • 一个key的别名
  • 一个key密码
  • 存储类型

位置,别名,两个密码和存储类型一个组成一个签名配置(SigningConfig)

默认状况下,debug签名配置使用一个debug keystore,已知的密码和已知的别名以及别名密码。 
debug keystore位于$HOME/.android/debug.keystore,若是没有的话会自动建立一个。

debug构建类型会自动使用debug SigningConfig。 

能够建立其它签名配置或者自定义默认内建配置。经过signingConfigs DSL容器来配置

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

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

    buildTypes {
        foo {
            debuggable true
            jniDebuggable true
            signingConfig signingConfigs.myConfig
        }
    }
}

上面的片断修改debug keystore的位置到项目根目录下。这会影响任何使用它的构建类型,在这个案例中,受影响的是debug构建类型。

这里也建立了一个新的签名配置和一个使用这个新签名配置的行的构建类型。

Note: 只有默认路径下debug keystore不存在的时候会被自动建立。改变debug keystore的路径则不会在新的路径下自动建立debug keystore。建立一个名字不一样的签名配置,可是使用默认的debug keystore路径,会自动建立debug keystore。也就是说,是否自动建立debug keystore,是由keystore的位置决定,而不是配置的名称。

Note: keystore的路径一般是项目根目录的相对路径,可是也可使用绝对路径,尽管不推荐这样(debug keystore除外,由于它会自动被建立)。

**Note: 若是你要把这些文件添加到版本控制系统中,你可能不想把密码写在文件中。下面的Stack Overflow链接提供了从从控制台或者环境变量读取的方法。 
http://stackoverflow.com/questions/18328730/how-to-create-a-release-signed-apk-file-using-gradle 
咱们之后会更新指南,提供更多的细节**

3.4.4 运行ProGuard

ProGuard从Gradle plugin for ProGuard 4.10开始支持的(since Gradle plugin 0.4)。若是构建类型的minifyEnabled属性被设置为true,那么Progruard插件会自动被添加进来,对应的任务也自动被建立。

Note: 从Gradle插件版本0.14.0开始BuildType.runProguard更改成minifyEnabled属性。具体请参考Release notes

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

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

Variant会使用全部声明的规则文件,包括声明在相应的Build Type和flavor中的。

SDK中有两个默认的规则文件:

  • proguard-android.txt
  • proguard-android-optimize.txt

它们位于sdk路径下,使用getDefaultProguardFile()能够获取文件的完整路径。它们除了是否要进行优化以外,其它都是相同的。

3.4.5 压缩资源文件

构建时能够自动移除没有被使用的资源文件。更多详细信息请查看文档资源文件压缩

4 依赖关系,Android库项目和多项目设置

Gradle项目能够依赖其它组件,这些组件能够是外部二进制包,或者其它Gradle项目。

4.1 依赖二进制包

4.1.1 本地包

为了配置一个外部库jar依赖,你须要在compile配置中添加一个依赖

dependencies {
    compile files('libs/foo.jar')
}

android {
    ...
}

Note: dependenciesDSL元素是标准Gradle API的一部分,并不属于android元素。

compile配置是用来编译main应用的。任何添加到编译路径中的东西都会被打包到最终的apk文件中。 
下面是其它一些在添加依赖时可能用到的配置:

  • compile: 主module
  • androidTestCompile: 测试module
  • debugCompile: debug构建类型的编译
  • releaseCompile: release构建类型的编译

由于构建一个apk必然有一个相关的构建类型,因此apk一般至少有两个编译配置:compile<buildtype>Compile 
建立一个构建类型时会自动建立一个基于它名字的编译配置<buildtype>Compile

当你在debug版本里须要使用一个自定义库(例如记录crash信息),而release版本不须要,或者他们依赖同一个库的不一样版本的时候,会很是有用。

也能够经过添加一个目录来依赖目录下的全部jar文件: 
compile fileTree(dir: 'libs', include: ['*.jar'])

4.1.2 远程文件

Gradle支持从Maven或者Ivy仓库获取依赖文件。

首先,必须把仓库添加到列表中,其次,必须按照Maven或者Ivy的文件声明规范来声明依赖。

repositories {
    mavenCentral()
}


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

android {
    ...
}

Note: mavenCentral()是指定仓库URL的便捷方式。Gradle支持远程和本地仓库。 
Note: Gradle遵循依赖关系的传递性。若是一个被依赖文件也依赖其它文件,那些被依赖的文件也会被拉取下来。

更多关于配置依赖的信息,请查看Gradle用户指南DSL文档

4.2 多项目设置

Gradle项目能够经过多项目设置依赖其它gradle项目。

一个多项目设置一般把全部子项目做为子目录放在指定的项目根目录下。

例如,项目结构以下:

MyProject/
 + app/
 + libraries/
    + lib1/
    + lib2/

咱们在这个结构中定义3个项目。Gradle将经过如下名字引用它们:

:app
:libraries:lib1
:libraries:lib2

每一个项目都有本身的build.gradle文件,声明来它怎样构建。另外,在根目录下还有一个settings.gradle文件,声明了全部的子项目。 
目录结构以下:

MyProject/
 | settings.gradle
 + app/
    | build.gradle
 + libraries/
    + lib1/
       | build.gradle
    + lib2/
       | build.gradle

settings.gradle文件的内容十分简单:

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

指明哪一个文件夹是一个实际的Gradle项目。 

:app项目或许依赖其它库项目,那么依赖关系声明以下:

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

更多关于多项目设置的信息在这里

4.3 库项目

在上面的多项目设置中,:libraries:lib1:libraries:lib2多是Java项目,:appAndroid项目将会使用它们输出的jar文件。

然而,若是你想要共享使用了Android API或者Android资源文件的代码(在库项目中使用了Android API或Android资源文件),这些库项目就不能是常规的Java项目,必须是Android库项目。

4.3.1 建立一个库项目

一个库项目和常规的Android项目很类似,只有不多的区别。

由于构建库项目和构建应用程序不同,因此使用不一样的插件。构建库项目的插件和构建应用程序的插件在内部共享大部分的代码,而且它们都是由com.android.tools.build.gradlejar库提供。

buildscript {
    repositories {
        mavenCentral()
    }

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

apply plugin: 'android-library'

android {
    compileSdkVersion 15
}

这是一个使用API 15编译的库项目。SourceSets和依赖关系的处理跟应用程序项目中同样,并且定制方式也同样。

4.3.2 普通项目和库项目的区别

一个库项目的主要输出是一个.aar包(它表明Android的归档文件)。它包含编译好的源码(例如jar文件或者本地.so文件)以及资源文件(manifest, res, assets)。 
一个库项目也能够生成一个测试apk来测试,而不依赖应用程序。

因为使用一样的锚点任务(assembleDebugassembleRelease),因此在命令行中构建库项目和普通项目没有区别。

其他部分,库项目和应用程序项目同样。都有构建类型和product flavors,能够生成多个版本的aar。 
要注意的是,多数Build Type配置不适用于库项目。然而,你能够定制sourceSet来改变所依赖库的内容,不论它是被普通项目使用仍是被测试。

4.3.3 引用一个库项目

引用一个库项目和引用其它项目的方式同样: 

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

Note: 若是你由多个库项目,那么顺序是很重要的。这和旧构建系统中的project.properties文件中的依赖顺序同样重要。

4.3.4 库项目发布

默认的状况下,库项目只会发布release变种版本(release variant)。这个版本会被全部引用了库项目的项目使用,无论它们本身构建的是什么版本。这是Gradle致使的限制,咱们正努力消除这个限制。

能够以下控制哪一个版本会被发布: 

android {
    defaultPublishConfig "debug"
}

要注意的是,这个发布配置名称必须是完整的variant名称,releasedebug这两个名称只有在没有flavor的时候才使用。若是想要在有flavor的时候改变默认的发布版本,你必须这样写:

android {
    defaultPublishConfig "flavor1Debug"
}

发布库项目的全部版本也是可能的。咱们计划在普通的项目依赖项目的工程中容许这种作法,可是因为Gradle的限制,如今还不能这么作(咱们也在努力修复这个问题)。

发布全部版本的功能默认没有开启。开启以下:

android {
    publishNonDefault true
}

必须认识到发布多个variant版本意味着发布多个aar文件,而不是在一个aar文件中包含了多个variant版本。每个aar文件就是一个独立的variant。

发布一个variant版本意味着构建出了一个可用的aar文件,做为Gradle项目的输出文件。这个文件能够发布到maven仓库,或者在其余项目依赖该库项目时做为依赖目标。

Gradle有默认文件的概念。下面这个就使用了默认文件:

compile project(':libraries:lib2')

为了依赖其余的发布版本,你必须指定具体使用哪个:

dependencies {
    flavor1Compile project(path: ':lib1', configuration: 'flavor1Release')
    flavor2Compile project(path: ':lib1', configuration: 'flavor2Release')
}

重要: 要注意已发布的配置是完整的variant版本,包含了构建类型,所以引用的时候也必须是完整的。

重要: 当开启了无默认版本发布,Maven发布插件会把这些额外的版本做为扩展包(按分类器)发布。这意味着并非真正兼容地发布到maven仓库。你应该发布一个独立的vatiant到仓库,或者开启发布全部配置来支持跨项目依赖。

5 测试

构建一个测试应用已经内置在应用项目内。不须要再建立单独的测试项目。

5.1 单元测试

试验性的单元测试功能支持已经加入到1.1中,具体请看这个页面。本节其余部分讲述的是”instrumentation tests”

5.2 基础和配置

正如前面提到的,紧邻着main sourceSet 的就是 androidTest sourceSet,默认在src/androidTest/路径下。

从这个sourceSet 会构建出一个使用Android测试框架,而且能够部署到设备上的测试apk来测试应用程序。这里面能够包含单元测试,集成测试,和后续UI自动化测试。

测试应用的<instrumentation>节点是自动生成的,可是你也能够建立一个src/androidTest/AndroidManifest.xml ,并在这个manifest文件中添加其余组件。

下面是一些测试应用能够配置的值:

  • testPackageName
  • testInstrumentationRunner
  • testHandleProfiling
  • testFunctionalTest

正如前面所看到的,这些在defaultConfig对象中配置:

android {
    defaultConfig {
        testPackageName "com.test.foo"
        testInstrumentationRunner "android.test.InstrumentationTestRunner"
        testHandleProfiling true
        testFunctionalTest true
    }
}

在测试应用程序的manifest文件中,instrumentation节点的targetPackage属性值会自动使用测试应用的package名称设置,即便这个名称是经过defaultConfig或者Build Type对象自定义的。这也是manifest文件须要自动生成的一个缘由。

另外,这个测试sourceSet也能够拥有本身的依赖。 
默认状况下,应用程序和他的依赖会自动添加的测试应用的classpath中,可是也能够经过如下来扩展:

dependencies {
    androidTestCompile 'com.google.guava:guava:11.0.2'
}

测试应用经过assembleTest任务来构建。assembleTest不依赖于main中的assemble 任务,须要手动设置运行,不能自动运行。

目前只有一个Build Type被测试。默认状况下是debug Build Type,可是这也能够经过如下自定义配置:

android {
    ...
    testBuildType "staging"
}

5.3 运行测试

正如前面提到的,检查经过锚点任务connectedCheck启动,这须要一个设备已链接。 
这个过程依赖于androidTest任务,所以将会运行androidTest。这个task将会执行下面内容: 

  • 确认应用和测试应用都被构建(依赖于assembleDebugassembleTest
  • 安装这两个应用
  • 运行这些测试
  • 卸载这两个应用.

若是有多于一个链接设备,那么全部测试都会同时运行在全部链接设备上。若是其中一个测试失败,无论是哪个设备,这个构建就失败。

全部测试结果都被保存为XML文档,路径为:

build/androidTest-results

(这和常规的JUnit相似,运行结果保存在build/test-results) 
一样,这也能够自定义配置:

android {
    ...

    testOptions {
        resultsDir = "$project.buildDir/foo/results"
    }
}

android.testOptions.resultsDir由Project.file(String)得到。

5.4 测试Android库

测试Android库项目的方法与应用项目的测试方法基本同样。

惟一的不一样在于整个库(包括它的依赖)都是自动做为依赖库被添加到测试应用中。结果就是测试APK不单只包含它的代码,还包含了库项目本身和库的全部依赖。 

库的manifest被组合到测试应用的manifest中(和其余项目引用这个库时同样)。

androidTest变成只是安装(或者卸载)测试APK(由于没有其它APK要安装)。

其它的部分都是相似的。

5.5 测试报告

当运行单元测试的时候,Gradle会输出一份HTML格式的报告以方便查看结果。 
Android plugin也是基于此,而且扩展了HTML报告文件,它将全部链接设备的报告都合并到一个文件里面。

5.5.1 独立项目

项目将会自动生成测试运行,测试报告默认位置:

build/reports/androidTests

这很是相似于JUnit的报告所在位置build/reports/tests,其它的报告一般位于build/reports/<plugin>/

这个路径也能够经过如下方式自定义:

android {
    ...

    testOptions {
        reportDir = "$project.buildDir/foo/report"
    }
}

报告将会合并运行在不一样设备上的测试结果。

5.5.2 多项目测试报告

在一个配置了多个应用或者多个库项目的项目中,当同时运行全部测试的时候,生成一个单一报告文件记录全部的测试多是很是有用的。

为了实现这个目的,须要使用同一个依赖文件中的另外一个插件。能够经过如下方式添加:

buildscript {
    repositories {
        mavenCentral()
    }

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

apply plugin: 'android-reporting'

这必须添加到项目的根目录下,例如与settings.gradle文件同个目录的build.gradle文件中。

而后,在命令行中导航到项目根目录下,输入如下命令就能够运行全部测试并合并全部报告:

gradle deviceCheck mergeAndroidReports --continue

注意:--continue 选项将容许全部测试,即便子项目中的任何一个运行失败都不会中止。若是没有这个选项,第一个失败测试将会终止所有测试的运行,这可能致使一些项目没有执行过它们的测试。

5.6 Lint支持

从0.7.0版本开始,你能够为项目中一个特定的variant版本运行lint,也能够为全部variant版本都运行lint。它将会生成一个报告描述哪个variant版本中存在着问题。

你能够经过如下lint选项配置lint。一般状况下你只须要配置其中一部分,如下列出了全部可以使用的选项:

android {
    lintOptions {
        // set to true to turn off analysis progress reporting by lint
        quiet true
        // if true, stop the gradle build if errors are found
        abortOnError false
        // if true, only report errors
        ignoreWarnings true
        // if true, emit full/absolute paths to files with errors (true by default)
        //absolutePaths true
        // if true, check all issues, including those that are off by default
        checkAllWarnings true
        // if true, treat all warnings as errors
        warningsAsErrors true
        // 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'
        // if true, don't include source code lines in the error output
        noLines true
        // if true, show all locations for an error, do not truncate lists, etc.
        showAll true
        // Fallback lint configuration (default severities, etc.)
        lintConfig file("default-lint.xml")
        // if true, generate a text report of issues (false by default)
        textReport true
        // location to write the output; can be a file or 'stdout'
        textOutput 'stdout'
        // if true, generate an XML report for use by for example Jenkins
        xmlReport false
        // file to write report to (if not specified, defaults to lint-results.xml)
        xmlOutput file("lint-report.xml")
        // if true, generate an HTML report (with issue explanations, sourcecode, etc)
        htmlReport true
        // optional path to report (default will be lint-results.html in the builddir)
        htmlOutput file("lint-report.html")

   // set to true to have all release builds run lint on issues with severity=fatal
   // and abort the build (controlled by abortOnError above) if fatal issues are found
   checkReleaseBuilds true
        // Set the severity of the given issues to fatal (which means they will be
        // checked during release builds (even if the lint target is not included)
        fatal 'NewApi', 'InlineApi'
        // Set the severity of the given issues to error
        error 'Wakelock', 'TextViewEdits'
        // Set the severity of the given issues to warning
        warning 'ResourceAsColor'
        // Set the severity of the given issues to ignore (same as disabling the check)
        ignore 'TypographyQuotes'
    }
}

6 构建不一样版本(Build Variants)

新构建系统的一个目标就是为一个应用构建不一样的版本。

有两个主要的场景: 

  • 同一个应用的不一样版本。例如,免费版和收费版 
  • 同一个应用,为了在Google Play Store上发布并适配多钟设备,打包出不一样的apk。
  • 以上两种状况的综合

也就是说,从同一个项目中生成这些不一样的apk,而不是使用一个库工程和2个以上的主应用工程。

6.1 产品定制(Product flavors)

一个product flavor定义了项目构建输出的一个自定义应用版本。一个单独项目能够有不一样的flavor,来生成不一样的应用。

这个新概念(flavor)是用来解决不一样应用版本间差别很小的情形。若是“这是否同一个应用?”的回答是确定的话,这是比使用库项目更好的作法。

flavor使用productFlavors 这个DSL容器来声明:

android {
    ....

    productFlavors {
        flavor1 {
            ...
        }

        flavor2 {
            ...
        }
    }
}

这里建立了两个flavor,分别是 flavor1 和 flavor2。 
注意: flavor的名字不能喝已有的构建类型(Build Type)名字冲突,或者和androidTest这个sourceSet的名字冲突。

6.2 构建类型+产品定制=变种版本(Build Type + Product Flavor = Build Variant)

前面已经提到,每个构建类型都会生成一个apk。忘了的话,请看3.4.2

Product Flavors 也会作一样的事情,实际上,项目输出来自全部可能的,Build Types和Product Flavors的组合,若是有Product Flavors的话。

每种Build Types和Product Flavors的组合就是一个Build Variant。

例如,默认的debug 和 release这两个Build Types,和上面建立的两个flavor会生成4个Build Variants:

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

没有flavor的项目也有Build Variants,使用默认的没有名字的flavor配置,使得Build Variants列表看起来和 Build Types同样。

6.3 ProductFlavor配置

每一个flavor在下面这样的闭包结构中配置:

android {
    ...

    defaultConfig {
        minSdkVersion 8
        versionCode 10
    }

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

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

注意到android.productFlavors.*android.defaultConfig的配置项类型相同,这意味着他们共享相同的属性。

defaultConfig为全部的flavor提供默认的配置,每一个flavor均可以覆盖配置项的值。上面的例子中,最终的配置以下:

  • flavor1 
    • packageName: com.example.flavor1
    • minSdkVersion: 8
    • versionCode: 20
  • flavor2 
    • packageName: com.example.flavor2
    • minSdkVersion: 14
    • versionCode: 10

一般,Build Type配置会覆盖其余配置。例如Build Type‘的packageNameSuffix会添加到Product Flavor‘的 packageName上。

也有一些状况下,一个配置项能够同时在Build Type 和 Product Flavor都进行配置,这时,就要具体状况具体分析了。

例如,signingConfig就是这样一个配置项。 
能够设置android.buildTypes.release.signingConfig让全部release版本使用同一个SigningConfig,也能够单独设置android.productFlavors.*.signingConfig让各release使用各自的SigningConfig。

6.4 源集合和依赖关系

和构建类型相似,产品flavor也能够经过他们本身的sourceSets影响最终的代码和资源

在上面的例子中,建立了四个sourceSet:

  • android.sourceSets.flavor1 
    位置 src/flavor1/
  • android.sourceSets.flavor2 
    位置 src/flavor2/
  • android.sourceSets.androidTestFlavor1 
    位置 src/androidTestFlavor1/
  • android.sourceSets.androidTestFlavor2 
    位置 src/androidTestFlavor2/

这些sourceSet 都会用来建立apk,和android.sourceSets.main以及构建类型的sourceSet一块儿。

下面是构建apk时,全部sourceSet的处理原则: 

  • 全部文件夹里的源码(src/*/java)都会被合并起来构建一个输出。
  • 多个Manifest文件会合并成一个。这样使得flavor和构建类型同样,能够有不一样的组件和permission
  • 全部资源的使用遵循优先级覆盖,Product Flavor资源覆盖main sourceSet资源,Build Type资源覆盖Product Flavor资源
  • 每一个Build Variant会从资源中生成各自的R文件(或者其余生成的源码)。各个Build Variant不会共享任何东西。

最后,和Build Type同样,Product Flavor还能够有本身的依赖。例如,flavor包含了一个广告版本和一个支付版本,那么就会依赖广告sdk,而其余版本不依赖。

dependencies {
    flavor1Compile "..."
}

在这个特别的状况下,src/flavor1/AndroidManifest.xml也许须要添加一个网络权限

每一个variant也会包含额外的sourceset:

  • android.sourceSets.flavor1Debug 
    位置 src/flavor1Debug/
  • android.sourceSets.flavor1Release 
    位置 src/flavor1Release/
  • android.sourceSets.flavor2Debug 
    位置 src/flavor2Debug/
  • android.sourceSets.flavor2Release 
    位置 src/flavor2Release/

这些sourceset比build type的sourceset有更高的优先级,容许variant级别的定制。

6.5 构建和任务

前面提到,每一个Build Type有本身的assemble<name>任务。可是Build Variant是Build Type 和 Product Flavor组合。

当使用Product Flavor的时候,更多的assemble-type任务会被建立出来,分别是:

  1. assemble\ 
    容许直接构建一个Variant版本,例如assembleFlavor1Debug。
  2. assemble\ 
    容许构建指定Build Type的全部APK,例如assembleDebug将会构建Flavor1Debug和Flavor2Debug两个Variant版本。
  3. assemble\ 
    容许构建指定flavor的全部APK,例如assembleFlavor1将会构建Flavor1Debug和Flavor1Release两个Variant版本。

assemble任务会构建全部可能的variant版本。

6.6 测试

测试多flavor的项目和简单项目十分相似。

androidTest sourceset被用来定义全部flavor的通用测试,同时,每一个flavor也能够有各自的测试。

正如上面提到的,测试各flavor的sourceSet会被建立:

  • android.sourceSets.androidTestFlavor1 
    位置 src/androidTestFlavor1/
  • android.sourceSets.androidTestFlavor2 
    位置 src/androidTestFlavor2/

一样,他们也能够有他们本身的依赖:

dependencies {
    androidTestFlavor1Compile "..."
}

能够经过锚点任务deviceCheck来运行测试,或者androidTest任务(当使用flavor时,它做为锚点任务)。

每一个flavor有本身的任务运行测试:androidTest<VariantName>。例如:

  • androidTestFlavor1Debug
  • androidTestFlavor2Debug

相似的,每一个variant都有构建测试apk和安装/卸载任务。

  • assembleFlavor1Test
  • installFlavor1Debug
  • installFlavor1Test
  • uninstallFlavor1Debug

最后,生成的HTML报告支持按照flavor合并。 
测试结果和报告位置以下,首先是每一个flavor版本的,而后是合并的。

  • build/androidTest-results/flavors/
  • build/androidTest-results/all/
  • build/reports/androidTests/flavors
  • build/reports/androidTests/all/

改变任一个路径,只会影响根目录,仍然会为每一个flavor和合并后的结果建立子目录。

6.7 多flaver维度的版本(Multi-flavor variants)

某些状况下,应用可能须要基于多个标准来建立多个版本。

例如,Google Play中multi-apk支持4个不一样的过滤器。为每个过滤器而建立的apk要求使用多个Product Flavor维度。

假设有一个游戏项目,有demo和付费版本,想要使用multi-apk中的ABI过滤器。因为要兼顾3种ABI和两个版本,因此须要生成6个apk(没有计算多个Build Type产生的版本)。

然而,付费版本的代码对于全部三个ABI都是同样,所以建立简单的6个flavor不是一个好方法。

相反的,将flavor分为两个维度,并自动构建全部可能的组合variant。

这个功能经过Flavor Dimensions来实现。flavor都被分配到一个特定的维度

android {
    ...

    flavorDimensions "abi", "version"

    productFlavors {
        freeapp {
            flavorDimension "version"
            ...
        }

        x86 {
            flavorDimension "abi"
            ...
        }
    }
}

android.flavorDimensions数组中定义可能的维度,而且每一个flavor都指定一个维度。

根据已经划分维度的flavor([freeapp, paidapp] 和 [x86, arm, mips]),和Build Type[debug, release],会建立如下variant:

  • x86-freeapp-debug
  • x86-freeapp-release
  • arm-freeapp-debug
  • arm-freeapp-release
  • mips-freeapp-debug
  • mips-freeapp-release
  • x86-paidapp-debug
  • x86-paidapp-release
  • arm-paidapp-debug
  • arm-paidapp-release
  • mips-paidapp-debug
  • mips-paidapp-release

android.flavorDimensions中定义维度的顺序很是重要。

每一个variant配置由多个Product Flavor对象决定:

  • android.defaultConfig
  • One from the abi dimension
  • One from the version dimension

维度的顺序决定哪一个flavor的配置会覆盖另外一个,这对资源来讲很重要,高优先级flavor中的资源会替换低优先级的。flavor维度定义时高优先级在前。因此上面的例子中:

abi > version > defaultConfig

多维flavor项目也有额外的sourceset,和variant相似,可是没有build type:

  • android.sourceSets.x86Freeapp 
    Location src/x86Freeapp/
  • android.sourceSets.armPaidapp 
    Location src/armPaidapp/
  • etc…

这些sourceset容许在flavor-combination的级别进行定制。他们比基础的flavor sourceset优先级高,可是比build type sourceset优先级低。

7 高级构建定制

7.1 构建选项

7.1.1 Java编译选项

android {
    compileOptions {
        sourceCompatibility = "1.6"
        targetCompatibility = "1.6"
    }
}

默认值是1.6。影响全部编译java源码的任务。

7.1.2 aapt选项

android {
    aaptOptions {
        noCompress 'foo', 'bar'
        ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
    }
}

影响全部使用aapt的任务。

7.1.3 dex选项
android {
    dexOptions {
        incremental false
        preDexLibraries = false
        jumboMode = false
        javaMaxHeapSize "2048M"
    }
}

影响全部使用dex的任务。

7.2 修改构建任务

基础的Java项目有一套有限的任务共同工做来生成输出。 

classes任务是一个编译Java源码的任务。很容易在build.gradle文件的脚本中用classes调用。这是project.tasks.classes的缩写。

在Android项目中,状况就有点复杂,由于存在大量一样的任务,他们的名字是基于Build Type 和 Product Flavor生成的。

为了解决这个问题,android有两个属性:

  • applicationVariants (只适用于 app plugin)
  • libraryVariants (只适用于 library plugin)
  • testVariants (二者都适用)

这三者分别返回一个ApplicationVariantLibraryVariant, 和 TestVariant对象的DomainObjectCollection

要注意使用这些collection中的任一个都会触发建立全部的任务。这意味着使用collection以后不该该修改配置。

DomainObjectCollection能够直接访问全部对象,或者经过过滤器筛选(更方便)。

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

全部三种variant共享下面这些属性:

Property Name Property Type Description
name String variant的名字,必须是惟一的
description String variant的描述
dirName String Variant的子文件夹名,必须是惟一的。可能也会有多个子文件夹,例如“debug/flavor1”
baseName String variant输出的基本名字,必须惟一
outputFile File Variant的输出,这是一个可读写的属性
processManifest ProcessManifest 处理Manifest的任务
aidlCompile AidlCompile 编译AIDL文件的的任务
renderscriptCompile RenderscriptCompile 编译Renderscript文件的任务
mergeResources MergeResources 合并资源文件的任务
mergeAssets MergeAssets 合并asset的任务
processResources ProcessAndroidResources 处理并编译资源文件的任务
generateBuildConfig GenerateBuildConfig 生成BuildConfig类的任务
javaCompile JavaCompile 编译Java源代码的任务
processJavaResources Copy 处理Java资源文件的任务
assemble DefaultTask variant的标志任务assemble

ApplicationVariant拥有如下额外属性:

Property Name Property Type Description
buildType BuildType variant的构建类型
productFlavors List Variant的ProductFlavor。通常不为空但容许空值
mergedFlavor ProductFlavor android.defaultConfig和variant.productFlavors的合并
signingConfig SigningConfig variant使用的SigningConfig对象
isSigningReady boolean 若是是true则代表这个variant已经具有了签名所需的全部信息
testVariant BuildVariant 将会测试这个variant的TestVariant
dex Dex 将代码打包成dex的任务,库工程该属性能够为空
packageApplication PackageApplication 打包出最终apk的任务,库工程该属性能够为空
zipAlign ZipAlign 对apk进行对齐(zipalign)的任务,库工程或者apk没法签名时,该属性能够为空
install DefaultTask 安装apk的任务,能够为空
uninstall DefaultTask 卸载任务

LibraryVariant拥有如下额外属性:

Property Name Property Type Description
buildType BuildType variant的构建类型
mergedFlavor ProductFlavor The defaultConfig values
testVariant BuildVariant 用于测试这个variant的Variant
packageLibrary Zip 打包成库工程AAR文件的任务,非库工程该属性为空

TestVariant拥有如下额外属性:

Property Name Property Type Description
buildType BuildType variant的构建类型
productFlavors List Variant的ProductFlavor。通常不为空但容许空值
mergedFlavor ProductFlavor android.defaultConfig和variant.productFlavors的合并
signingConfig SigningConfig variant使用的SigningConfig对象
isSigningReady boolean 若是是true则代表这个variant已经具有了签名所需的全部信息
testedVariant BaseVariant 被当前TestVariant测试的BaseVariant
dex Dex 将代码打包成dex的任务,库工程该属性能够为空
packageApplication PackageApplication 打包出最终apk的任务,库工程该属性能够为空
zipAlign ZipAlign 对apk进行对齐(zipalign)的任务,库工程或者apk没法签名时,该属性能够为空
install DefaultTask 安装apk的任务,能够为空
uninstall DefaultTask 卸载任务
connectedAndroidTest DefaultTask 在已链接的设备上运行android测试的任务
providerAndroidTest DefaultTask 使用扩展API运行android测试的任务

API for Android specific task types.

android特有任务的API:

  • ProcessManifest 
    • File manifestOutputFile
  • AidlCompile 
    • File sourceOutputDir
  • RenderscriptCompile 
    • File sourceOutputDir
    • File resOutputDir
  • MergeResources 
    • File outputDir
  • MergeAssets 
    • File outputDir
  • ProcessAndroidResources 
    • File manifestFile
    • File resDir
    • File assetsDir
    • File sourceOutputDir
    • File textSymbolOutputDir
    • File packageOutputFile
    • File proguardOutputFile
  • GenerateBuildConfig 
    • File sourceOutputDir
  • Dex 
    • File outputFolder
  • PackageApplication 
    • File resourceFile
    • File dexFile
    • File javaResourceDir
    • File jniDir
    • File outputFile 
      • 直接在Variant对象中使用“outputFile”能够改变最终的输出文件。
  • ZipAlign 
    • File inputFile
    • File outputFile 
      • 直接在Variant对象中使用“outputFile”能够改变最终的输出文件。

因为Gradle的工做方式和Android plugin的配置方式, 每一个task类型的API是受限的。 
首先,Gradle使得任务只能配置输入输出的路径和一些可能使用的选项标识。所以,任务只定义一些输入或者输出。

其次,大多数任务的输入都很复杂,通常都混合了sourceSet、Build Type和Product Flavor中的值。为了保持构建文件的简单,可读,咱们的目标是让开发者经过略微改动DSL对象来修改构建过程,而不是深刻到输入文件和任务选项中去。

另外须要注意,除了ZipAlign这个任务类型,其它全部类型都要求设置私有数据来让它们运行。这意味着不能手动建立这些任务的实例。

这些API也可能改变。大致来讲,当前的API是围绕着修改任务的输入(可能的话)和输出来添加额外的处理过程(必要的话)。欢迎反馈,特别是那些没有预见到的问题。

对于Gradle任务(DefaultTask, JavaCompile, Copy, Zip),请参考Gradle文档。

7.3 BuildType和Product Flavor属性参考)

敬请期待。 
对于Gradle任务(DefaultTask, JavaCompile, Copy, Zip),请参考Gradle文档。

7.4 使用(JDK)1.7版本的sourceCompatibility)

使用Android KitKat(buildTools v19)就可使用diamond operator,multi-catch,在switch中使用字符串,try with resource等等(jdk7中的新特性),要使用这些,须要修改你的构建文件以下:

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 19
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}

注意:你能够将minSdkVersion的值设置为19以前的版本,只是你只能使用除了try with resources以外的语言特性。若是你想要使用try with resources特性,你就须要把minSdkVersion也设置为19。

你一样也须要确认Gradle使用1.7或者更高版本的JDK。(Android Gradle plugin也须要0.6.1或者更高的版本)

相关文章
相关标签/搜索