原文Gradle Plugin User Guide - Android Tools Project Site
samples see bottom of New Build System
参考Gradle For Android Training Coursehtml
这篇文档是基于0.9版本的Gradle插件,1.0之前的版本因为不兼容,可能会有所不一样java
新构建系统的目标是:android
Gradle是一个高级构建系统和构建工具,容许经过插件自定义构建逻辑git
如下一些功能使得咱们选择Gradle:api
Gradle项目经过项目根目录下的 build.gradle 文件来描述构建过程数组
最简单的Java项目构建文件 build.gradle安全
apply plugin: 'java'
这个脚本应用了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版本,和构建工具版本是必须的。在脚本中,对应的是compileSdkVersion
和buildtoolsVersion
属性。compileSdkVersion
和旧编译系统中project.properties
文件中的target
属性对应。这个新属性compileSdkVersion
能够是一个int值(API Level)或者一个和以前的target
属性值同样的字符串
重点: 你应该只应用android插件,同时应用java插件会致使构建错误
注意: 你一样须要一个local.properties
文件来指明SDK的路径,和build.gradle
在同一路径下,在文件中使用sdk.dir
属性指明。或者,你能够设置ANDROID_HOME
环境变量。二者是一致的,你能够选择一种你喜欢的方式。
前面的android构建脚本使用了默认的文件夹目录结构。Gradle遵循约定优于配置
的原则,在可能的状况下提供了合理的默认配置参数。
基本的项目包含两个“source sets”组件。main source code
和test code
,位于如下的目录中:
src/main/ src/androidTest/
在这些目录中,都存在目录对应源码组件
无论是Java仍是Android插件,源码目录和资源目录都以下 :
java/ resources/
对于Android插件,还有特有的文件和目录
AndroidManifest.xml res/ assets/ aidl/ rs/ jni/
Note: src/androidTest/AndroidManifest.xml
不是必须的,会自动被建立。
当默认项目结构不合适的时候,能够配置项目目录。根据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’ 示例(位于本页面底部)中展现了这部份内容
在build文件中应用一个插件将自动建立一系列构建任务。Java插件和Android插件都是这样。任务约定以下:
组合项目输出
执行全部检查
执行assemble和check两个task的全部工做
清理项目输出
任务assemble
, check
和 build
不会作任何实际的事情。他们只是锚点任务(anchor tasks),插件依赖他们来添加实际执行实际操做的任务。
这样就不须要考虑项目是什么类型,使用的是什么插件,均可以执行一样的任务。
例如,使用findbugs插件,会建立新的任务,并让check
依赖这个任务,使得check
被调用时这个任务就会被调用。
在终端(命令行,gradle项目目录下)中运行下面的任务能够查询到高级别的任务:
gradle tasks
运行如下命令能够看到所有任务和任务依赖关系:
gradle tasks --all
Note: Gradle自动监视一个任务声明的输入输出文件。再次执行构建任务时,若是文件没有改变,Gradle会指明全部任务为UP-TO-DATE
,意味着任务不须要执行。这样的话,任务能够正确地互相依赖,而不不会致使非必须的构建操做
Java插件主要建立两个任务,下面是这两个锚点任务的依赖关系
jar
任务直接或间接地依赖其余任务:例如classes
任务将编译Java源码
testClasses
任务用于编译测试的,可是这个任务不多被调用,由于test
任务依赖于它(就像依赖classes
任务同样)
一般来讲,你只须要调用assemble
或者check
任务,而不须要调用其余任务。
你能够在Gradle Java插件文档看到Java插件的所有任务和它们的描述
Android插件使用一样的约定来保持和其余插件的兼容,而且添加了额外的锚点任务:
assemble
这个任务组织项目的输出
check
这个项目运行全部检查
connectedCheck
运行检查须要一个已链接的设备或者模拟器。并在全部已链接的设备上异步运行。
deviceCheck
经过APIs链接远程设备并运行检查。这一般在CI服务器上运行。
build
运行assemble
和check
clean
清理项目输出
新的锚点任务是必须的,以保证在不须要设备链接的状况下能运行常规检查。
须要注意的是,build
任务并不依赖deviceCheck
或者connectedCheck
一个Android项目至少有两个输出:debug APK 和 release APK。它们每个都有本身的锚点任务来帮助它们完成独立的构建:
它们都依赖其它任务来完成构建一个apk所须要的多个步骤。assemble
任务依赖这两个任务,因此调用assemble
会生成两个APK。
Tip: Gradle支持在命令行中使用camel形式的任务名缩写。
例如:
gradle aR
和gradle assembleRelease
是同样的,由于没有别的任务名有一样的缩写
锚点任务check
也有本身的依赖:
最终,插件会为全部构建类型(debug, release, test)建立install
/uninstall
任务,若是输出文件能够安装的话(必须签名)。
Android插件提供了大量DSL来直接从构建系统中定制大多数事情。
经过DSL,能够配置如下manifest属性:
例如:
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文件,除非真的必要。
默认状况下,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>/
这意味这新的构建类型的名字不能是main或者androidTest(这是插件强制要求的),而构建类型的名称必须是惟一的。
像其它sourceSet同样,构建类型的sourceSet能够从新被定向:
android { sourceSets.jnidebug.setRoot('foo/jnidebug') }
另外,每个Build Type都会建立一个assemble<BuildTypeName>
任务。
在前面,assembleDebug
和assembleRelease
已经提到过了,这就是它们的来源。当debug和release构建类型被预建立的时候,它们相关的任务就被自动建立了,好比assembleDebug
和assembleRelease
上面的build.gradle片断一样会建立assembleJnidebug
任务,assemble
会像依赖assembleDebug
和assembleRelease
任务同样依赖assembleJnidebug
。
Tip: 你能够在命令行下输入gradle aJ
来运行assembleJnidebug
任务。
可能用到的场景:
BuildType的源码和资源经过如下方式使用:
对一个应用程序签名须要如下:
位置,别名,两个密码和存储类型一个组成一个签名配置(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
咱们之后会更新指南,提供更多的细节**
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中有两个默认的规则文件:
它们位于sdk路径下,使用getDefaultProguardFile()能够获取文件的完整路径。它们除了是否要进行优化以外,其它都是相同的。
构建时能够自动移除没有被使用的资源文件。更多详细信息请查看文档资源文件压缩
Gradle项目能够依赖其它组件,这些组件能够是外部二进制包,或者其它Gradle项目。
为了配置一个外部库jar依赖,你须要在compile
配置中添加一个依赖
dependencies { compile files('libs/foo.jar') } android { ... }
Note: dependencies
DSL元素是标准Gradle API的一部分,并不属于android
元素。
compile
配置是用来编译main应用的。任何添加到编译路径中的东西都会被打包到最终的apk文件中。
下面是其它一些在添加依赖时可能用到的配置:
compile
: 主moduleandroidTestCompile
: 测试moduledebugCompile
: debug构建类型的编译releaseCompile
: release构建类型的编译由于构建一个apk必然有一个相关的构建类型,因此apk一般至少有两个编译配置:compile
和<buildtype>Compile
建立一个构建类型时会自动建立一个基于它名字的编译配置<buildtype>Compile
当你在debug版本里须要使用一个自定义库(例如记录crash信息),而release版本不须要,或者他们依赖同一个库的不一样版本的时候,会很是有用。
也能够经过添加一个目录来依赖目录下的全部jar文件:
compile fileTree(dir: 'libs', include: ['*.jar'])
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文档
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') }
更多关于多项目设置的信息在这里。
在上面的多项目设置中,:libraries:lib1
和:libraries:lib2
多是Java项目,:app
Android项目将会使用它们输出的jar文件。
然而,若是你想要共享使用了Android API或者Android资源文件的代码(在库项目中使用了Android API或Android资源文件),这些库项目就不能是常规的Java项目,必须是Android库项目。
一个库项目和常规的Android项目很类似,只有不多的区别。
由于构建库项目和构建应用程序不同,因此使用不一样的插件。构建库项目的插件和构建应用程序的插件在内部共享大部分的代码,而且它们都是由com.android.tools.build.gradle
jar库提供。
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.5.6' } } apply plugin: 'android-library' android { compileSdkVersion 15 }
这是一个使用API 15编译的库项目。SourceSets
和依赖关系的处理跟应用程序项目中同样,并且定制方式也同样。
一个库项目的主要输出是一个.aar
包(它表明Android的归档文件)。它包含编译好的源码(例如jar文件或者本地.so文件)以及资源文件(manifest, res, assets)。
一个库项目也能够生成一个测试apk来测试,而不依赖应用程序。
因为使用一样的锚点任务(assembleDebug
, assembleRelease
),因此在命令行中构建库项目和普通项目没有区别。
其他部分,库项目和应用程序项目同样。都有构建类型和product flavors,能够生成多个版本的aar。
要注意的是,多数Build Type配置不适用于库项目。然而,你能够定制sourceSet
来改变所依赖库的内容,不论它是被普通项目使用仍是被测试。
引用一个库项目和引用其它项目的方式同样:
dependencies { compile project(':libraries:lib1') compile project(':libraries:lib2') }
Note: 若是你由多个库项目,那么顺序是很重要的。这和旧构建系统中的project.properties
文件中的依赖顺序同样重要。
默认的状况下,库项目只会发布release变种版本(release variant)。这个版本会被全部引用了库项目的项目使用,无论它们本身构建的是什么版本。这是Gradle致使的限制,咱们正努力消除这个限制。
能够以下控制哪一个版本会被发布:
android { defaultPublishConfig "debug" }
要注意的是,这个发布配置名称必须是完整的variant名称,release
和debug
这两个名称只有在没有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到仓库,或者开启发布全部配置来支持跨项目依赖。
构建一个测试应用已经内置在应用项目内。不须要再建立单独的测试项目。
试验性的单元测试功能支持已经加入到1.1中,具体请看这个页面。本节其余部分讲述的是”instrumentation tests”
正如前面提到的,紧邻着main
sourceSet 的就是 androidTest
sourceSet,默认在src/androidTest/
路径下。
从这个sourceSet 会构建出一个使用Android测试框架,而且能够部署到设备上的测试apk来测试应用程序。这里面能够包含单元测试,集成测试,和后续UI自动化测试。
测试应用的<instrumentation>
节点是自动生成的,可是你也能够建立一个src/androidTest/AndroidManifest.xml
,并在这个manifest文件中添加其余组件。
下面是一些测试应用能够配置的值:
正如前面所看到的,这些在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" }
正如前面提到的,检查经过锚点任务connectedCheck
启动,这须要一个设备已链接。
这个过程依赖于androidTest任务,所以将会运行androidTest。这个task将会执行下面内容:
assembleDebug
和assembleTest
)若是有多于一个链接设备,那么全部测试都会同时运行在全部链接设备上。若是其中一个测试失败,无论是哪个设备,这个构建就失败。
全部测试结果都被保存为XML文档,路径为:
build/androidTest-results
(这和常规的JUnit相似,运行结果保存在build/test-results)
一样,这也能够自定义配置:
android { ... testOptions { resultsDir = "$project.buildDir/foo/results" } }
android.testOptions.resultsDir
由Project.file(String)得到。
测试Android库项目的方法与应用项目的测试方法基本同样。
惟一的不一样在于整个库(包括它的依赖)都是自动做为依赖库被添加到测试应用中。结果就是测试APK不单只包含它的代码,还包含了库项目本身和库的全部依赖。
库的manifest被组合到测试应用的manifest中(和其余项目引用这个库时同样)。
androidTest
变成只是安装(或者卸载)测试APK(由于没有其它APK要安装)。
其它的部分都是相似的。
当运行单元测试的时候,Gradle会输出一份HTML格式的报告以方便查看结果。
Android plugin也是基于此,而且扩展了HTML报告文件,它将全部链接设备的报告都合并到一个文件里面。
项目将会自动生成测试运行,测试报告默认位置:
build/reports/androidTests
这很是相似于JUnit的报告所在位置build/reports/tests
,其它的报告一般位于build/reports/<plugin>/
这个路径也能够经过如下方式自定义:
android { ... testOptions { reportDir = "$project.buildDir/foo/report" } }
报告将会合并运行在不一样设备上的测试结果。
在一个配置了多个应用或者多个库项目的项目中,当同时运行全部测试的时候,生成一个单一报告文件记录全部的测试多是很是有用的。
为了实现这个目的,须要使用同一个依赖文件中的另外一个插件。能够经过如下方式添加:
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
选项将容许全部测试,即便子项目中的任何一个运行失败都不会中止。若是没有这个选项,第一个失败测试将会终止所有测试的运行,这可能致使一些项目没有执行过它们的测试。
从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' } }
新构建系统的一个目标就是为一个应用构建不一样的版本。
有两个主要的场景:
也就是说,从同一个项目中生成这些不一样的apk,而不是使用一个库工程和2个以上的主应用工程。
一个product flavor
定义了项目构建输出的一个自定义应用版本。一个单独项目能够有不一样的flavor,来生成不一样的应用。
这个新概念(flavor)是用来解决不一样应用版本间差别很小的情形。若是“这是否同一个应用?”的回答是确定的话,这是比使用库项目更好的作法。
flavor使用productFlavors
这个DSL容器来声明:
android { .... productFlavors { flavor1 { ... } flavor2 { ... } } }
这里建立了两个flavor,分别是 flavor1
和 flavor2
。
注意: flavor的名字不能喝已有的构建类型(Build Type)名字冲突,或者和androidTest
这个sourceSet的名字冲突。
前面已经提到,每个构建类型都会生成一个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:
没有flavor的项目也有Build Variants,使用默认的没有名字的flavor配置,使得Build Variants列表看起来和 Build Types同样。
每一个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均可以覆盖配置项的值。上面的例子中,最终的配置以下:
一般,Build Type配置会覆盖其余配置。例如Build Type‘的packageNameSuffix
会添加到Product Flavor‘的 packageName
上。
也有一些状况下,一个配置项能够同时在Build Type 和 Product Flavor都进行配置,这时,就要具体状况具体分析了。
例如,signingConfig
就是这样一个配置项。
能够设置android.buildTypes.release.signingConfig
让全部release版本使用同一个SigningConfig,也能够单独设置android.productFlavors.*.signingConfig
让各release使用各自的SigningConfig。
和构建类型相似,产品flavor也能够经过他们本身的sourceSets影响最终的代码和资源
在上面的例子中,建立了四个sourceSet:
src/flavor1/
src/flavor2/
src/androidTestFlavor1/
src/androidTestFlavor2/
这些sourceSet 都会用来建立apk,和android.sourceSets.main
以及构建类型的sourceSet一块儿。
下面是构建apk时,全部sourceSet的处理原则:
最后,和Build Type同样,Product Flavor还能够有本身的依赖。例如,flavor包含了一个广告版本和一个支付版本,那么就会依赖广告sdk,而其余版本不依赖。
dependencies { flavor1Compile "..." }
在这个特别的状况下,src/flavor1/AndroidManifest.xml
也许须要添加一个网络权限
每一个variant也会包含额外的sourceset:
src/flavor1Debug/
src/flavor1Release/
src/flavor2Debug/
src/flavor2Release/
这些sourceset比build type的sourceset有更高的优先级,容许variant级别的定制。
前面提到,每一个Build Type有本身的assemble<name>
任务。可是Build Variant是Build Type 和 Product Flavor组合。
当使用Product Flavor的时候,更多的assemble-type任务会被建立出来,分别是:
assemble
任务会构建全部可能的variant版本。
测试多flavor的项目和简单项目十分相似。
androidTest
sourceset被用来定义全部flavor的通用测试,同时,每一个flavor也能够有各自的测试。
正如上面提到的,测试各flavor的sourceSet会被建立:
src/androidTestFlavor1/
src/androidTestFlavor2/
一样,他们也能够有他们本身的依赖:
dependencies { androidTestFlavor1Compile "..." }
能够经过锚点任务deviceCheck
来运行测试,或者androidTest
任务(当使用flavor时,它做为锚点任务)。
每一个flavor有本身的任务运行测试:androidTest<VariantName>
。例如:
相似的,每一个variant都有构建测试apk和安装/卸载任务。
最后,生成的HTML报告支持按照flavor合并。
测试结果和报告位置以下,首先是每一个flavor版本的,而后是合并的。
改变任一个路径,只会影响根目录,仍然会为每一个flavor和合并后的结果建立子目录。
某些状况下,应用可能须要基于多个标准来建立多个版本。
例如,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:
android.flavorDimensions
中定义维度的顺序很是重要。
每一个variant配置由多个Product Flavor对象决定:
维度的顺序决定哪一个flavor的配置会覆盖另外一个,这对资源来讲很重要,高优先级flavor中的资源会替换低优先级的。flavor维度定义时高优先级在前。因此上面的例子中:
abi > version > defaultConfig
多维flavor项目也有额外的sourceset,和variant相似,可是没有build type:
src/x86Freeapp/
src/armPaidapp/
这些sourceset容许在flavor-combination的级别进行定制。他们比基础的flavor sourceset优先级高,可是比build type sourceset优先级低。
android { compileOptions { sourceCompatibility = "1.6" targetCompatibility = "1.6" } }
默认值是1.6。影响全部编译java源码的任务。
android { aaptOptions { noCompress 'foo', 'bar' ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~" } }
影响全部使用aapt的任务。
android { dexOptions { incremental false preDexLibraries = false jumboMode = false javaMaxHeapSize "2048M" } }
影响全部使用dex的任务。
基础的Java项目有一套有限的任务共同工做来生成输出。
classes
任务是一个编译Java源码的任务。很容易在build.gradle
文件的脚本中用classes
调用。这是project.tasks.classes
的缩写。
在Android项目中,状况就有点复杂,由于存在大量一样的任务,他们的名字是基于Build Type 和 Product Flavor生成的。
为了解决这个问题,android
有两个属性:
这三者分别返回一个ApplicationVariant
, LibraryVariant
, 和 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:
因为Gradle的工做方式和Android plugin的配置方式, 每一个task类型的API是受限的。
首先,Gradle使得任务只能配置输入输出的路径和一些可能使用的选项标识。所以,任务只定义一些输入或者输出。
其次,大多数任务的输入都很复杂,通常都混合了sourceSet、Build Type和Product Flavor中的值。为了保持构建文件的简单,可读,咱们的目标是让开发者经过略微改动DSL对象来修改构建过程,而不是深刻到输入文件和任务选项中去。
另外须要注意,除了ZipAlign这个任务类型,其它全部类型都要求设置私有数据来让它们运行。这意味着不能手动建立这些任务的实例。
这些API也可能改变。大致来讲,当前的API是围绕着修改任务的输入(可能的话)和输出来添加额外的处理过程(必要的话)。欢迎反馈,特别是那些没有预见到的问题。
对于Gradle任务(DefaultTask, JavaCompile, Copy, Zip),请参考Gradle文档。
敬请期待。
对于Gradle任务(DefaultTask, JavaCompile, Copy, Zip),请参考Gradle文档。
使用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或者更高的版本)