《巧用Gradle构建Android应用》读书笔记

  1. 1. 查漏补缺
    1. 1.1. 第一章:Android 开发 Gradle 基础
      1. 1.1.1. 1.5 添加 Java 库的依赖
    2. 1.2. 从项目导入到发布
      1. 1.2.1. 2.1 设置项目属性
      2. 1.2.2. 2.5 在项目之间分享设置
    3. 1.3. 构建类型和定制
      1. 1.3.1. 3.1 处理构建类型
      2. 1.3.2. 3.2 产品定制和变种
      3. 1.3.3. 3.3 合并资源
      4. 1.3.4. 3.4 定制维度
      5. 1.3.5. 3.5 合并不同定制间的 Java 源代码
    4. 1.4. 自定义任务
      1. 1.4.1. 4.1 编写自定义任务
      2. 1.4.2. 4.3 排除任务
      3. 1.4.3. 4.4 自定义代码集
    5. 1.5. 测试
    6. 1.6. 性能和文档

《巧用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']
}
}

测试

性能和文档