首页 > 编程知识 正文

Android Gradle学习记录4 Gradle概念及工作流程,工作流程概念

时间:2023-05-06 12:02:11 阅读:183394 作者:1889

对于Android而言,我们一般依托于AndroidStudio来使用Gradle,
因此这里就不浪费笔墨单独介绍Gradle的下载和配置了。

Gradle是一个编译打包工具,但实际上它也是一个编程框架。
Gradle有自己的API文档,对应链接如下:
https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
由此可以看出,编写Gradle脚本时,我们实际上就是调用Gradle的API编程。

1 基本组件
Project:
Gradle中,每一个待编译的工程都是一个Project。
例如,用AndroidStudio构建项目时,每一个module都是Gradle定义的Project。

Task:
每一个Project在构建的时候都包含一系列的Task。
比如一个Android APK的编译可能包含:
Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task等。

对于Gradle的编译打包流程而言,Task就是最小的执行单元,
其中将调用具体的函数来完成实际的工作。

Plugin:
一个Project到底包含多少个Task,在很大程度上依赖于编译脚本指定的插件。
插件定义了一系列基本的Task,并指定了这些Task的执行顺序。

整体来看,Gradle作为一个框架,负责定义通用的流程和规则;
根据不同的需求,实际的编译工作则通过具体的插件来完成。
例如,编译Java项目时使用Java插件、编译Groovy项目时使用Groovy插件等。

举个例子来说,我们在Android APK对应的build.gradle中经常可以看到如下代码:

apply plugin: 'com.android.application'

这就是使用编译APK的插件。
同样,在编译Android Library时可以看到如下代码,用于指定使用编译Library的插件:

apply plugin: 'com.android.library'

2 具体示例
为了更好理解Gradle中的组件及编译方法,我们来看个例子。

如上图所示,NetworkFramework目录下包含两个Module:
其中一个是Android App,另一个是Android Library。
按照Gradle的定义,这两个Module都是单独的Project。

从上图可以看出,每个Gradle Project在其根目录下都需要一个build.gradle文件。
build.gradle文件就是该Project的编译脚本。

每个Gradle Project都可以独立编译。
具体的做法是:
进入到Project的根目录,然后利用gradle命令执行某个Task。
例如,当我们需要编译app时,只需要进入到app的根目录,
然后执行如下命令(gradle需要添加到环境变量中):

gradle assemble

其中,assemble是一个Task的名称,由Android对应的插件定义。
我们可以用如下命令,查看当前插件定义的所有Task:

//查看根目录包含的taskgradle tasks//可以指定目录,查看某个具体Project的task//例如在NetworkFramework目录下,查看app包含的task://gradle app:tasks

该命令执行后的效果类似于:

除了单独编译一个Project以外,Gradle还支持多个Project同时编译,即Multi-Projects Build。

还是以上图中的例子来进行说明。
对于AndroidStudio而言,上图是一个Project,包含了两个Module。
对于Gradle而言,这就是一个Multi-Projects。

如上图中的红线所示,Android Project成为Gradle Multi-Projects的关键:
在其根目录定义了build.gradle和settings.gradle文件。
定义build.gradle的后,我们就可以直接在Android Project根目录下执行gradle assemble命令,同时编译app和library。
build.gradle的内容类似于:

// Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript { repositories { //jcenter是一个函数,表示编译过程中依赖的库, //所需的插件可以在 jcenter 仓库中下载 jcenter() } //定义编译脚本依赖的库 dependencies { //表示我们编译的时候,依赖android开发的gradle插件 classpath 'com.android.tools.build:gradle:2.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }}//针对所有子Projectallprojects { repositories { jcenter() }}task clean(type: Delete) { delete rootProject.buildDir}

settings.gradle则主要定义了根目录下具体有多少个Gradle Project,
其内容类似于:

include ':app', ':library'

我们可以利用gradle projects查看Multi-Projects与其子Project的关系,
如下图所示:

显示子Project的数量,完全由settings.gradle来决定。

settings.gradle除了可以include外,还可以设置一些函数。
这些函数会在gradle构建整个工程任务的时候执行,
因此可以在settings做一些初始化工作。

//定义函数def test = { println "Before build"}//调用函数test()include ':app', ':library'

此时,在Multi-Project的根目录执行gradle assemble的结果类似于:

从图中可以看出,settings.gradle中定义的test函数在整个构建开启前就执行了。

3 Gradle工作流程
在本篇博客的最后,我们来看一下Gradle的工作流程:

如上图所示,Gradle的工作流程基本包含三个阶段。
首先是初始化阶段,对于Multi-Project而言,就是执行settings.gradle。

初始化阶段结束后,整个工作流程进入到配置阶段。
配置阶段的目标是解析每个子Project中的build.gradle,
建立一个有向图来描述各个Task之间的依赖关系。

配置阶段完成后,就进入执行阶段了,开始依次运行Task进行实际的工作。

从上图可以看出,我们可以在不同的阶段之间增加一些定制化的Hook,
以便在不同阶段的开始和结束进行一些特殊的操作。

我们在Multi-Projects根目录的build.gradle文件中(还可以在每个子Project的build.gradle中增加Hook),增加上图所示的Hook:

.................gradle.beforeProject {project-> println "beforeProject: " + project}gradle.taskGraph.whenReady { graph-> println "graphWhenReady: " + graph}gradle.buildFinished { result-> println "buildFinished:" + result}

然后执行gradle assemble看看对应的输出:

可以看出,初始化阶段完成后,依次对每个子Project执行了beforeProject Hook。
当两个子Project的配置阶段都完成后,才执行了taskGraph.whenReady Hook。


整个编译过程全部完成后,才最后执行了buildFinished Hook。

我们在子Project的build.gradle中增加一些Hook并进行编译:

从图中可以看出,会先形成Multi-Projects整体的Task有向图,
然后才会形成各个子Project的Task有向图(从回调Hook的顺序推断的,实际情况可能需要进一步参考文档确定)。

4 总结
本篇博客我们介绍了Gradle的基本概念及工作流程,
现在我们知道了Gradle的编译其实就是按顺序执行一系列的Task。
那么,我们只需要进一步知道如何定义Task之间的依赖关系,
以及如何使用Groovy定义我们需要的Task,就能定制出我们需要的编译流程了。
这部分内容我们在下一篇博客中继续介绍。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。