2 基本项目配置(Basic Project Setup)
Gradle项目的构建描述文件为位于项目根目录下的build.gradle文件。(查看Gradle构建系统的用户指南)
2.1 简单的构建文件(Simple build files)
最简单的Android项目的build.gradle文件内容如下:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.1.0"
}
该Android构建文件有三个主要部分:
buildscript { ... }
配置驱动构建的代码。该实例中声明使用JCenter中央仓库资源,并且声明依赖于该Maven工件(artifact)的一个类路径(classpath)。这个工件(artifact)是一个包含1.3.1版本Android插件的Gradle库。注意:该配置只作用于代码构建过程,并非应用于项目本身,项目需要声明属于自己的仓库(Repositories)及依赖(Dependencies),这在稍后会提及。
接下来,应用com.android.application插件。该插件用于构建Android应用。
最后,android { ... }
配置了所有Android构建的参数。这是Android DSL的入口点。默认情况下,只有配置编译版本和编译工具版本,即compileSdkVersion和buildtoolsVersion属性。该编译版本相当于旧构建系统中project.properites的target属性,新属性可以与旧target属性一样配置int类型(API版本号)或者string类型的值。
重点:你只需要应用com.android.application插件,同时应用java插件会导致构建错误。
注意:你同样需要在相同路径添加local.properties文件,并使用sdk.dir属性设置本地SDK路径。另外,你也可以通过设置ANDROID_HOME环境变量。这两种方式没有什么不同,你可以选择一个你喜欢的方式。local.properties文件示例:
sdk.dir=/path/to/Android/Sdk
2.2 项目结构(Project Structure)
上面提到的基本构建文件需要一个默认的文件夹结构。Gradle遵循约定优于配置的概念,尽可能地提供合理的默认配置参数。基本的项目存在两个“源集合(source sets)”的组件,即主要源代码和测试代码。它们分别位于:
- src/main/
- src/androidTest/
在这些目录下存在着每个源组件对应的子目录。对于Java及Android插件,Java源码和Java资源文件路径为:
- java/
- resources/
对于Android插件,存在特定的额外文件和文件夹:
- AndroidManifest.xml
- res/
- assets/
- aidl/
- rs/
- jni/
- jniLibs/
这意味着主要源码集(source sets)的.java文件位于src/main/java目录,主要清单(manifest)文件为src/main/AndroidManifest.xml
注意:*src/androidTest/AndroidManifest.xml*是不需要的,它会自动被创建。
2.2.1 配置项目结构(Configuring the Structure)
当默认的项目结构不适当时,就需要进行手动配置。查看Gradle文档,了解在纯java项目中这是如何做到的。
Android插件使用了类似的语法,但是由于使用的是自己的源集合(SourceSets),所以需要在android { ... }
块中设置。在以下示例中,使用了旧的项目结构(Eclipse结构)的主要源代码,并且重新映射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')
}
}
注意:因为旧的项目结构将所有的源文件(Java,AIDL及RenderScript)放置在相同目录,所以我们需要重新映射源集合(sourceSet)中所有组件到src目录。
注意:setRoot()将移动整个源集合(sourceSet)及其子目录到新目录下。示例中将src/androidTest/*目录移动到tests/*目录。这是Android的特殊配置,在Java源集合(sourceSets)中无效。
2.3 构建任务(Build Tasks)
2.3.1 一般任务(General Tasks)
应用一个插件到构建文件将自动创建一系列构建任务去运行,Java插件及Android插件都是如此。任务的约定如下:
- assemble 该任务组合项目的运行输出
- check 该任务运行所有检查
- build 该任务运行
assemble
任务和check
任务 - clean 该任务清空项目的运行输出
assemble任务,check任务和build任务并未做确切的工作,仅仅只是作为“锚”任务,而插件则依赖它们来做一些确切的工作。
这就允许你总是调用相同的任务,而不必考虑是什么类型的项目,或者应用了什么插件。例如,应用findbugs插件将会提交一个新的任务,同时使check任务依赖于此任务,使得每当check任务被调用时此任务同样被调用到。
在命令行中,你可以执行以下命令获取到高级别的任务:
gradle tasks
获取所有任务列表和它们之间的依赖关系,可以运行以下命令:
gradle tasks --all
注意:Gradle自动监视一个任务声明的输入输出。
运行build任务两次,并且期间未做任何修改,Gradle报告所有任务为UP-TO-DATE状态,这表明任务不需要运行。这使得任务可以通过正确的依赖关系,从而避免不必要的构建操作。
2.3.2 Java项目任务(Java project tasks)
这是由Java插件创建的最重要的两个任务,依赖于主要的锚任务:
-
assemble
- jar 该任务创建输出
-
check
- test 该任务运行测试
jar任务直接或间接地依赖于其他任务:例如classes用于编译Java代码。测试则是由testClasses来编译的,但是作为test的依赖很少使用(类似classes)。
通常情况下,你可能只需要调用assemble或check任务,不需要调用其他任务。你可以查看Gradle文档获取Java插件的所有任务及其描述。
2.3.3 Android任务(Android tasks)
Android插件使用同样的约定来保证与其他插件的兼容性,同时也添加了额外的锚任务:
- assemble 该任务组装项目的运行输出
- check 该任务运行所有检查
- connectedCheck 运行检查需要一个已连接设备或虚拟机,将会同时运行在所有已连接设备
- deviceCheck 使用API连接到远程设备运行检查,用于CI服务器
- build 该任务运行
assemble
任务及check
任务 - clean 该任务清空项目的运行输出
新的锚任务是必须的,主要用于保证无设备连接时能够运行定期检查。注意build未依赖于deviceCheck或connectedCheck。
一个Android项目至少有两个输出:debug版本APK和release版本APK。每个输出也都有各自的锚任务来帮助构建:
-
assemble
- assembleDebug
- assembleRelease
它们都依赖于其他任务来完成构建APK所需要运行的多个步骤。其中assemble
任务依赖于这两个任务,所以调用assemble
时会导致构建两个APK。
提示:Gradle命令行支持任务名称的骆驼格式缩写。例如:
gradle aR
等同于执行以下命令:
gradle assembleRelease
只要没有名称与'aR'重复的任务即可
check锚任务有自己的依赖关系:
-
check
- lint
-
connectedCheck
- connectedAndroidTest
-
deviceCheck
- 该任务依赖于其他插件实现测试扩展的任务
最后,所有能被安装(需要签名)的构建类型(debug,release,test),插件会为其创建安装任务和卸载任务,如:
- installDebug
- installRelease
-
uninstallAll
- uninstallDebug
- uninstallRelease
- uninstallDebugAndroidTest
2.4 基本构建定制(Basic Build Customization)
Android插件提供一个广泛的DSL用于直接从构建系统定制大部分功能。
2.4.1 清单条目(Manifest entries)
通过DSL可以配置最重要的清单(manifest)条目,例如:
- minSdkVersion
- targetSdkVersion
- versionCode
- versionName
- applicationId(有效的packageName,了解ApplicationId与PackageName)
- testApplicationId(用于test APK)
- testInstrumentationRunner
示例:
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
versionCode 12
versionName "2.0"
minSdkVersion 16
targetSdkVersion 23
}
}
请查看Android插件DSL参考来获取完整的可配置构建属性及默认值。
将清单(manifest)属性放在构建文件中的好处在于可以动态地调整这些值。例如,可以通过读取文件或者使用其他自定义的逻辑来获取版本名称:
def computeVersionName() {
...
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
versionCode 12
versionName computeVersionName()
minSdkVersion 16
targetSdkVersion 23
}
}
注意:不要使用在该范围内会导致冲突的getter方法名称。例如在defaultConfig { ...}
里调用getVersionName()
方法,将自动调用defaultConfig.getVersionName()
而不是自定义方法。
2.4.2 构建类型(Build Types)
默认情况下,Android插件自动设置项目构建一个应用程序的debug和release版本。它们最大的不同在于是否能够在一个安全设备(非开发版)上调试应用以及APK如何签名。debug版本是通过一个已知的用户名/密码自动创建的key/certificate进行签名(在构建中签名以防止未签名提示)。release版本在构建中并未签名,需要稍后进行签名。
这些配置通过一个BuildType对象来配置。默认情况下,创建了debug和release两个实例。Android插件允许定制这两个实例,并且创建其他的构建类型(Build Type)。可以在buildTypesDSL容器中配置:
android {
buildTypes {
debug {
applicationIdSuffix ".debug"
}
jnidebug {
initWith(buildTypes.debug)
packageNameSuffix ".jnidebug"
jniDebuggable true
}
}
}
以上代码实现以下功能:
- 配置默认的debug构建类型(Build Type),设置包名为\
.debug,使得debug和release版本的apk能安装在同一个设备上。 - 创建名为
jnidebug
的构建类型(Build Type),并设置为debug构建类型(Build Type)的副本。 - 继续配置
jnidebug
,开启JNI组件的调试模式,并添加一个不同的包名后缀。
创建一个新构建类型(Build Type)与在buildTypes下使用新元素一样容易,可以调用initWith()
或者使用闭包配置。查看DSL参考获取在构建类型(Build Type)中所有可配置属性。
除了用来修改构建属性,构建类型(Build Type)也可以用来添加特定代码或资源。对于每个构建类型(Build Type),都会创建一个相对应的源集合(SourceSet),默认的位置为src/\
与其他的源码集合(source sets)一样,构建类型(Build Type)的源目录可以重定向:
android {
sourceSets.jnidebug.setRoot('foo/jnidebug')
}
另外,对于每个编译类型(Build Type),都会创建一个新的assemble\
提示:记住,你可以输入gradle aJ
来运行assembleJnidebug
任务。
可能使用的情况:
- 只在调试模式下权限
- 在调试模式下的自定义实现
- 调试模式下不同的资源(例如与签名证书相关的资源)
构建类型(Build Type)下的代码/资源,遵循以下使用规则:
- 清单(manifest)文件合并到app的清单(manifest)文件
- 代码作为另外一个源代码目录
- 资源覆盖主资源,替换已存在的资源
2.4.3 签名配置(Signing Configurations)
一个应用签名需要以下信息(查看签名你的应用了解关于签名APK的详情):
- keystore
- keystore密码
- key alias名称
- key alias密码
- 存储类型
keystore位置、key alias名称与密码,及存储类型组成了一个签名配置。默认情况下,debug配置使用了一个已知的密码和已知的key作为调试的keystore。调试的keystore位于$HOME/.android/debug.keystore
,如果不存在的话会自动创建。debug构建类型(Build Type)自动设置使用调试SigningConfig。
允许创建其他配置或者自定义默认配置,只需通过signingConfigs
DSL容器:
android {
signingConfigs {
debug {
storeFile file("debug.keystore")
}
myConfig {
storeFile file("other.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
}
buildTypes {
foo {
signingConfig signingConfigs.myConfig
}
}
}
以上代码片段更改调试keystore的位置到项目的根目录。这会自动影响到使用该配置的任何构建类型(Build Type),比如debug
构建类型(Build Type)。同时也创建一个新的签名配置和一个使用该配置的新构建类型(Build Type)。
注意:只有位于默认位置的调试keystore会自动创建,变更后的路径不会自动创建调试keystore。如果创建一个使用默认调试keystore的签名配置,会使之自动创建调试keystore。换句话说,这与keystore的位置相关,而不是配置名称。
注意:keystore的位置通常相对于项目根目录,也可以设置绝对路径,但并不推荐。
注意:如果你提交这些文件到版本控制中,你可能不希望在文件中配置密码,Overflow提供了从控制台或者环境变量读取密码的方式。