《巧用Gradle构建Android应用》读书笔记,适合入门以及查漏补缺。

查漏补缺

第一章:Android 开发 Gradle 基础

1.5 添加 Java 库的依赖

通过 -x 标志来不执行某一任务:

1
./gradlew assembleDebug -x lintDebug

依赖的完整语法:

1
testCompile group: 'junit', name: 'junit', version: '4.12'

依赖的快捷语法:

1
testCompile 'junit:junit:4.12'

版本号以变量的形式(不推荐):

1
testCompile 'junit:juint:4.+'

这告诉 Gradle 任何高于 4.0 版本的 JUnit 在编译项目的测试时是必须的。


禁用传递依赖

1
compile group: 'com.android.support', name: 'appcompat-v7', version: '24.2.0', transitive: false

只引入模块 jar 的快捷语法

1
compile 'com.nineoldandroids:library:2.4.0@jar'

从项目导入到发布

2.1 设置项目属性

“extra” 属性

1
2
3
4
5
6
7
ext {
dagger2Version = '2.0'
}
dependencies {
compile "com.google.dagger:dagger:${dagger2Version}"
apt "com.google.dagger:dagger-compiler:${dagger2Version}"
}

如果不想将实际的用户名和密码放到构建文件中,可以放到项目根目录下的 gradle.properties 文件:

1
2
login = 'user'
pass = '123'

然后替换成变量

1
2
3
4
5
6
7
8
9
repositories {
maven {
url 'http://xxx'
credentials {
username login
password pass
}
}
}

gradle.properties 或命令行提供变量,可以使用 -P 传参给 gradle

1
./gradlew -P login=me -P passowrd=123 assembleDebug

当某个变量同时在 ext 和 gradle.properties 设置了,最终是以 gradle.properties 中设置的值为准,如果通过命令行 -P 的方式传参的话,最后是以命令行的方式的值为准。

2.5 在项目之间分享设置

在顶层 gradle 构建文件中使用 allprojects 或者 subprojects

1
2
3
subprojects {
apply plugin: 'com.android.library'
}

subprojects 属性返回所有子项的集合,subprojects 方法将提供的闭包应用到其中的每一个项目

构建类型和定制

3.1 处理构建类型

给应用程序 ID 和版本添加后缀

1
2
3
4
5
6
7
8
android {
buildTypes {
debug {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
}
}
}

3.2 产品定制和变种

使用 Android 闭包的 productFlavors 块来申明一个产品的定制

1
2
3
4
5
6
7
8
9
10
android {
productFlavors {
dev {
applicationId 'com.yydcdut.note.dev'
}
store360 {
applicationId 'com.yydcdut.note.s360'
}
}
}

每个产品定制可以拥有其自己的值,如下面的属性,还有一下其他的基于默认的 defaultConfig 的相同属性:

  1. applicationId
  2. minSdkVersion
  3. targetSdkVersion
  4. versionCode
  5. versionName
  6. signingConfig

每个定制定义了自己的源代码集和资源,其与主带吗集是兄弟关系。除了 app/src/main/java 以外,你还可以添加源文件在如下目录:

1
2
app/src/dev/java
app/src/store360/java

还可以添加额外的资源文件到如下目录:

1
2
app/src/dev/res
app/src/store360/res/layout

3_2

3.3 合并资源

通过合并项目定制和构建类型的 res 文件夹以及主要的目录树来合并资源。优先级是:构建类型覆盖产品定制,其覆盖 main 代码集。

非 Java 的资源会互相覆盖,构建类型拥有最高优先级,其次是构建定制,然后是 main 目录。

3.4 定制维度

当一个产品定制还不够,还需要另外一个标准类区分应用程序的不同版本,可以在产品定制中添加 flavorDimensions 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
android {
flavorDimensions 'product', 'client'

productFlavors {
dev {
dimension 'product'
applicationId 'com.yydcdut.note.dev'
}
store360 {
dimension 'product'
applicationId 'com.yydcdut.note.s360'
}
zhangsan {
dimension 'client'
}
lisi {
dimension 'client'
}
}
}

3_4

两种构建类型( debug 和 release ),两种产品(product)定制( dev 和 store360 ),两种客户(client)定制( zhangsan 和 lisi )。

同样 client 定制也可以定义自己的源代码集和资源。

flavorDimensions 标签在 gradle 构建的时候将 product 列在了 client 之前,意味着产品维度中的值相对于客户维度拥有更高的优先级。

3.5 合并不同定制间的 Java 源代码

自定义任务

4.1 编写自定义任务

在 configuration 阶段, Gradle 根据其依赖配置构建一个 DAG,然后执行目标任务,随着其依赖一起。所有任务在执行前先被配置。

如果你需要执行命令,添加一个 doLast 块到你的 Gradle 任务中:

1
2
3
4
5
6
7
task myTask {
doLast {
android.applicationVariants.all { variant ->
println variant.name
}
}
}

这个任务中无论在 doLast 之前还是之后的所有事情都在配置阶段执行。在 doLast 块中的代码在运行阶段执行。

applicationVariants 属性只针对 com.android.application 插件有效。 libraryVariants 属性针对 Android 库项目可用,两者都可以使用 testVariants 属性。

4.3 排除任务

使用 -x 标志排除一个单独的任务,通过修改任务图来排除多个任务。

1
./gradlew build -x lint

这样做排除了 lint 任务以及其所有的依赖。

1
2
3
gradle.taskGraph.whenReady { graph -> 
graph.allTasks.findAll { it.name == ~/lint.*/ }*.enable = false
}

任务图的 allTasks 属性调用的是 getAllTasks 方法,结果就是所有的名字以 lint 开头的任务的 enable 属性都被设置成 false,这些任务都不会运行。

4.4 自定义代码集

在 Gradle 构建中使用 sourceSets 来达到使用非标准目录为源代码目录,下面的是 API 23 的 samples 中的栗子,在 input/BasicGestureDetect 目录中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// The sample build uses multiple directories to
// keep boilerplate and common code separate from
// the main sample code.
List<String> dirs = [
'main', // main sample code; look here for the interesting stuff.
'common', // components that are reused by multiple samples
'template'] // boilerplate code that is generated by the sample template process

android {
sourceSets {
main {
dirs.each { dir ->
java.srcDirs "src/${dir}/java"
res.srcDirs "src/${dir}/res"
}
}
androidTest.setRoot('tests')
androidTest.java.srcDirs = ['tests/src']
}
}

测试

性能和文档