二十八、安卓工程师必须了解的Gradle知识

3,151 阅读5分钟

概述

Android中使用的编译工具就是 gradle,通常我们使用工程默认生成的 build.gradle就能满足基本需求。但是涉及到复杂的工程结构设计,更优雅的配置写法,这就要求我们对gradle有更深的了解。

首先以下概念是必须要掌握的。

Gradle的构建生命周期

一个安卓项目,从源代码 java 和 资源文件 到最终产物 apk,中间有很多过程,大概可以分为三个大步骤。

  1. 初始化(Initialization):在这一阶段,Gradle 将加载项目的构建配置文件(build.gradle)并创建 Gradle 构建对象。它会解析项目的结构、依赖关系和其他配置,并准备构建过程所需的资源和插件。
  2. 配置(Configuration):在这一阶段,Gradle 将根据初始化阶段中加载的构建配置文件来配置项目的构建。它会执行各个模块的配置任务,解析依赖关系,确定编译选项,处理资源文件,应用插件等。这个阶段主要是确定构建的行为和内容,即告诉 Gradle 应该如何构建项目。
  3. 执行(Execution):在这一阶段,Gradle 将根据配置阶段中确定的构建行为来执行实际的构建任务。它会按照指定的顺序执行各个任务,如编译源代码、处理资源文件、运行单元测试、打包 APK 等。这个阶段是构建过程的实际执行阶段,Gradle 会根据配置和任务之间的依赖关系来自动执行所需的任务。

Task

Task 任务,是gradle工作的基本单元。gradle执行编译动作,都是通过一个个task来进行的.

自定义task

image.png

Task之间存在依赖关系

指定依赖关系有很多种方式,下图是其中一种最简单的。 image.png

Gradle的构建生命周期中, 配置阶段 会将 所有task的依赖关系确定下来。

Gradle自定义方法

image.png

利用def 关键字可以定义一个 方法,写法和java完全类似。并且可以在task中 使用此方法。

利用系统提供的Task构建自己的task

以下就是 创建了我们自己的 copy 任务,并且继承了 系统自带的 Copy任务。 image.png

比如我们现有的目录结构是:

image.png

执行完任务之后,目录结构如下:

image.png

我们自定义copy任务的作用就是,将 src内的所有文件,原样拷贝到 dest目录。

至于这里具体有多少个系统的 type 供我们选择,就需要去gradle的官网阅读文档,而且每一个 gradle版本都会有所不同。

project

一个安卓工程,在 gradle作用下,会生成一个 rootProject对象。 而 工程下的每一个module,都会是一个Project。

比如下图中,我们的整个工程就是一个 RootProject,其余每一个module都是 Project。

image.png

我们可以在 rootProject下统筹管理所有的子project,也就是说,我们能做到 在 根目录的build.gradle中,一次性管理所有 module中的依赖配置。

举个很实用的例子:

我们的项目经过长时间的迭代,会引入很多第三方库,而且有的第三方库会有同一个依赖库的版本的冲突,造成编译失败。常用的解决方式是,在出问题的 module 的 build.gradle中强行指定某个 依赖库的版本。

image.png

但是这种是属于特例,如果这种特例写的太多,我们自己多个module之间的特例也有可能形成冲突。所以最好的办法,就是在 根目录的 build.gradle 中进行统筹管理这些特例。比如下图:

image.png subprojects{} 实际上是在对所有的子module进行遍历。

project.configurations.all{} 则是对一个module中的所有配置进行遍历

resolutionStrategy.eachDependency{} 又是在对一个配置中的所有依赖进行遍历。

经过了三重遍历,最终得到了每个module的每一个依赖配置。

最终,通过group和name,锁定一个依赖,并通过 details.useVersion() 来指定统一的版本号。

这种写法,比在每一个module中进行分别强制指定依赖版本要好得多。

但是仍有一个缺点,那就是 AndroidStudio无法提供代码提示,上图中的${cfgs.androidSupportVersion} 全部都要手动输入或者拷贝。

buildSrc

buildSrc是 编写 gradle插件的其中一种方式,我们在安卓工程中,与app平级,创建一个 buildSrc目录,它是 一个特殊的module,它内部的所有代码,都会转化成gradle插件内容。

buildSrc是解决上面的缺点一个可靠的方式。

在 buildSrc中创建一个 build.gradle.kts文件,并添加 kotlin插件,

image.png

当然,为了编译通过,我们还要引入jcenter仓库。

创建 buildSrc/src/main/java目录,并在其中新建 Dependencies.kt,并添加两个类。 image.png

Version类中指定所有可能使用到的配置版本。 image.png

Deps类中,添加所有依赖,如下图,这是kotlin的语法,其中每一个依赖的字符串都引用到了 上面的Version张的变量。 image.png

然后我们就可以 用如下写法去编写依赖 :

image.png

最可贵的是,我们在写出Deps.之后,它会默认带出所有的可用的值。

image.png

总结

Task是gradle工作的基本单元,每次编译时,都会在 控制台看到很多gradle task正在执行。

image.png

每一个project都是由多个task组合而成,每个 module 都包含一个build.gradle,每个build.gradle都会被gradle编译成 project字节码,build.gradle中的所有逻辑,都映射成了project字节码的实现逻辑。

最后buildSrc是我们解决 编写 build内容没有代码提示的 简单有效的办法。