Android Studio 占领市场后,构建工具 Gradle 的地位无人能比,我们有必要学习、使用它来为我们创造价值。
在深入学习 Gradle 之前,我们有必要了解下它为什么这么流行。
Android 应用的构建过程
Android 应用程序的构建过程非常复杂,如图所示:
主要有以下几步:
- 主要的资源文件(layout, values 等)都被 aapt 编译,并且在一个 R 文件中引用
- Java 代码被 Java 编译器编译成 JVM 字节码(.class 文件)
- JVM 字节码再被 dex 工具转换成 dalvik 字节码(.dex 文件)
- 然后这些 .dex 文件、编译过的资源文件和其他资源文件(比如图片)会被打包成一个 apk
- apk 文件在安装前会被 debug/release 的 key 文件签名
- 安装到设备
几个注意点
- 上面的步骤中***步注意是主要的资源文件,有些特别的资源文件就不会被编译,比如 assets 目录下的文件,raw 目录下的文件还有图片,都不会被编译。只不过 raw 下的文件会在 R 文件里生成 id
- 如果对 apk 正式签名,还需要使用 zipalign 工具对 apk 进行对齐操作,这样做的好处是当应用运行时会减少内存的开销
通过上面的介绍可以看到,这么复杂的构建过程如果需要人手动去完成未免太过残忍,于是有了各种的构建工具。
Android 构建的旧爱:Ant, Maven
在 Gradle 之前被广泛使用的是 Apache Ant 和 Maven。
Ant
Ant 2000 年发布,很快成为 Java 项目***的构建工具。
Ant 的优点就是:
- 简单、易学,不需要什么特殊准备就能上手
- 基于过程式编程思想使得构建非常灵活
- 后来还能支持插件。
不足之处就是使用 XML 作为脚本配置格式,除非是很小的项目,否则它的 XML 文件很快就大得无法管理。
Maven
Maven 发布于 2004 年。目的是解决使用 Ant 所带来的一些问题。
Maven 也是使用 XML 作为构建配置的文件格式,不过文件结构却有了巨大的变化:
- Ant 需要开发者将执行 task 所需的全部命令都列出来
- 而 Maven 依靠约定并提供现成的可调用的目标
不仅如此,Maven 更重要的一个进步是具备从网络上自动下载依赖的能力(当然 Ant 后来通过 Ivy 也具备了这个功能),这革命性地改变了我们开发软件的方式。
Maven 的缺点是:
- 依赖管理不能很好地处理相同库文件不同版本之间的冲突(Ivy在这方面更好一些)
- XML 作为配置文件的格式有严格的结构层次和标准,定制化目标很困难
Maven 主要解决了依赖管理的问题,然而使用 XML 的错误使它重蹈覆辙,实际上用 Maven 很难写出复杂、定制化的构建脚本,在大型项目中,它经常什么“特别的”事还没干就有几百行代码,甚至不如 Ant。
前辈们在反省前两种构建工具的错误之后,提出了 DSL (Domain Special Language, 领域专用语言)的概念,目标是设计一套能够解决特定领域问题的语言。在构建这方面,DSL 的一个成功案例就是 Gradle。
Android 构建的新欢:Gradle
2012 年发布的 Gradle 深刻吸取前面几位前辈的经验和教训,集大家之所成,做了很多改进。
Gradle 有约定优于配置的原则,即为设置和属性提供默认值,这使得它比 Ant 或者 Maven 更容易上手。
Gradle 构建脚本不再使用 xml ,而是使用基于 Groovy 的 DSL 进行书写(Groovy 是一种基于 Java 虚拟机的动态语言,因此 Android 开发者看着会很熟悉),从而使得构建脚本比用 Ant 和 Maven 写的更清晰、简洁,下面是实现同样目标的 Maven 代码和 Gradle 代码对比:
Gradle 既有 Ant 的强大和灵活,又有 Maven 的依赖管理,支持插件且易于使用。因此一推出就获得广泛关注,2013 年被 Google 选为 Android Studio 的默认构建工具。
Gradle 设计的方式使得它可以很容易地扩展构建和插入到现有的构建过程中,Google 推广 Gradle 和 Android Studio 时,目标是让代码复用、构建 variant、配置和定制构建过程变得更加简单。
有人可能担心是否需要专门去学习新语言 Groovy,《Gradle for Android》书中专门提到:
Groovy 代码非常易读,如果你学习过 Java,那么学习 Groovy 的曲线不会陡峭。 如果你想构建自己的任务和插件,那么对 Groovy 有更深层次的理解尤为重要。 不过因为 Groovy 是基于 Java 虚拟机的,所以你完全可以用 Java 或者其他基于 Java 虚拟机的语言来编写你的自定义插件。
Gradle 的关键概念及构建生命周期
Gradle 中两个关键的概念:项目和任务。
每个 build.gradle 构建脚本文件代表一个项目 project:
任务 task 定义在构建脚本里:
每次构建至少包括一个项目,每个项目里又至少包括一个任务。
构建生命周期
一个 Gradle 构建通常包括下面三个阶段:
1.初始化
项目实例会在这时被创建,如果这个项目里有多个 module,或者依赖多个 library,并且它们都有对应的 build.gradle 文件,就会创建多个项目实例
2.配置
在这个阶段构建脚本被执行,并且为每个项目实例创建和配置任务
3.执行
在这个阶段 Gradle 将根据构建脚本的配置决定哪些任务会被执行
不同任务之间可能有 相互依赖,因此在配置阶段 Gradle 会生产依赖关系图,没有依赖的任务通常会被优先执行,然后一个接一个执行其他任务。一旦一个任务被执行过,就不会被再次执行。
Gradle Wrapper
Gradle 在不断的发展,有可能存在新版本不兼容旧版本的情况,于是官方为我们提供了 Gradle Wrapper,就是为了兼容和适配不同版本,确保构建是可重复的。
普通的 Gradle 脚本命令是:
- gradle ...
而 Gradle Wrapper 命令只是在 gradle 后加了个 w:
- gradlew ...
在 Mac 下略微有些不同:
- ./gradlew ...
开发者或者自动构建系统可以通过使用 wrapper 来运行 gradle 命令,由它来搞定兼容等问题。因此我们甚至都不需要安装 gradle,直接使用 gradle wrapper 即可,就像 Android Studio 里推荐的一样:
上图我并没有使用 wrapper,是因为当你运行 gradlew 命令时,gradle wrapper 会自动下载需要但是你没有的 gradle 版本并使用。 这在多人协作时,很可能因为别人修改了 gradle 版本、上传到 git,然后导致你运行命令时需要下载半天。
不过官方还是推荐使用 wrapper,毕竟这样更稳定。
总结
这篇文章对比 Ant 和 Maven 介绍了 Gradle 的一些优点和基础概念,在理解 Gradle 为什么会被使用、它有什么优点之后,有助于我们后续深入学习 Gradle 的使用。