一、Gradle 生命周期与生命周期的hook
1、生命周期的三个阶段
初始化阶段(Initialization):决定哪些项目参与编译。
Gradle会决定构建中包含哪些项目,并会为每个项目创建Project实例。为了决定构建中会包含哪些项目,Gradle首先会寻找settings.gradle
来决定此次为单项目构建还是多项目构建。
配置阶段(Configuration):解析配置,会生成Task注册表。
在 Configuration (配置) 阶段,Gradle会评估构建项目中包含的所有构建脚本,随后应用插件、使用DSL配置构建,并在最后注册Task。简单的说,配置阶段就是创建Projec对象,执行我们的build.gradle文件,根据代码创建对应的Task依赖关系图。
Gradle执行阶段(Execution):依次执行Task。
Gradle会执行构建所需的Task集合
总结: 简单来说,就是Gradle通过settings.gradle在初始化阶段决定哪些项目参与编译,确定后每个project在配置阶段解析配置,会生成Task注册表。最后,在执行阶段依次执行Task
2、Hook生命周期
Gradle在生命周期各个阶段都提供了用于回调的钩子函数,如下图:
初始化阶段(Initialization):
在settings.gradle执行完后,会回调Gradle对象的settingsEvaluated方法;
在构建所有工程build.gradle对应的Project对象后,即初始化阶段完毕,会回调Gradle对象的projectsLoaded方法。
配置阶段(Configuration):
Gradle会循环执行每个工程的build.gradle脚本文件;
在执行当前工程build.gradle前,会回调Gradle对象的beforeProject方法和当前Project对象的beforeEvaluate方法。虽然beforeEvalute属于project的生命周期,但是此时buildscript尚未被加载,所以beforeEvaluate的设置依然要在init script或setting script中进行,不要在 build script中使用project.beforeEvaluate方法;
在执行当前工程build.gradle后,会回调Gradle对象的afterProject方法和当前Project对象的afterEvaluate方法;
在所有工程的build.gradle执行完毕后,会回调Gradle对象的projectsEvaluated方法;
在构建Task依赖有向无环图后,也就是配置阶段完毕,会回调TaskExecutionGraph对象的whenReady方法。
Gradle执行阶段(Execution):
Gradle会循环执行Task及其依赖的Task;
在当前Task执行之前,会回调TaskExecutionGraph对象的beforeTask方法;
在当前Task执行之后,会回调TaskExecutionGraph对象的afterTask方法;
当所有的Task执行完毕后,会回调Gradle对象的buildFinish方法。
提示:Gradle执行脚本文件的时候会生成对应的实例,主要有如下几种对象:
Gradle对象:在项目初始化时构建,全局单例存在,只有这一个对象;
Project对象:每一个build.gradle文件都会被转换成一个Project对象,类似于maven中的pom.xml文件;
Settings对象:settings.gradle会转变成一个settings对象,和整个项目是一对一的关系,一般只用到include方法;
Task对象: 从前面的有向无环图中,我们也可以看出,gradle最终是基于Task的,一个项目可以有一个或者多个Task。
3、案例
setting.gradle
println("---Gradle:初始化阶段")
gradle.settingsEvaluated {
println("---Gradle:settingsEvaluated Settings对象评估完毕")
}
gradle.projectsLoaded {
println("---Gradle:projectsLoaded 准备加载Project对象了")
println("---Gradle:初始化阶段结束")
println("---Gradle:配置阶段开始")
}
gradle.projectsEvaluated {
println("---Gradle:projectsEvaluated 所有Project对象评估完毕")
println("---Gradle:配置阶段结束")
}
gradle.allprojects{
beforeEvaluate {
println("---Gradle:Projec beforeEvaluate Project开始评估,对象是 = "+project.name)
}
afterEvaluate {
println("---Gradle:Projec afterEvaluate Project评估完毕,对象是 = " + project.name)
}
}
gradle.taskGraph.whenReady {
println "---Gradle:taskGraph whenReady打印task ...start"
gradle.taskGraph.getAllTasks().each {task ->
println("${task.path}")
}
println "---Gradle:taskGraph whenReady打印task ...end"
println("---Gradle:执行阶段开始,开始执行task")
}
gradle.taskGraph.beforeTask {
task -> println "---Gradle:task: ${task.name} of the project ${task.getProject().name} beforeTask.."
}
gradle.taskGraph.afterTask {
task -> println "---Gradle:task: ${task.name} of the project ${task.getProject().name} afterTask.."
}
gradle.buildFinished {
println("---Gradle:buildFinished 构建结束了")
println("---Gradle:执行阶段结束")
}
参考文件 blog.csdn.net/qq_37475168…
二、Gradle Task
1、是什么
Task
是一个任务,是Gradle
中最小的构建单元
。Task管理了一个Action
的List,你可以在List前面插入一个Action(doFirst),也可以从list后面插入(doLast),Action是最小的执行单元
。
Task是Gradle构建的核心对象,Task可以接收输入、执行某些操作,并根据执行的操作产生输出。
2、思考
Gradle构建的核心就是在配置阶段构建了由Task组成的有向无环图
因此,我们在学习、使用Task也是基于这个有向无环图,插入TasK,或者在现有Task中插入Action
3、学习方向
Task 创建
Task插入当前有向无环图中
在现有Task的基础上插入Action
4、案例
在现有Task中插入Action:统计build耗时
//统计build 阶段耗时
project.afterEvaluate {
println("---配置阶段打印 " + project.name)
def startTime
def endTime
def perBuildTask = project.tasks.getByName("preBuild")
def buildTask = project.tasks.getByName("assembleOverseasDebug")
//在构建开始,结束时插入Action,计算构建时间
//Action1 在项目构建开始见记录开始时间
perBuildTask.doFirst {
startTime = System.currentTimeMillis()
println("---perBuildTask任务开始前" + startTime)
}
//Action2 在项目构建结束后记录结束时间
buildTask.doLast {
endTime = System.currentTimeMillis()
println("---buildTask结束后" + endTime)
}
}
Task插入到当前的有向无环图中
task taskA {
doLast {
println "taskA 执行"
}
}
task taskB {
doLast {
println "taskB 执行"
}
}
//在preBuild后面插入一个任务
project.afterEvaluate {
// dependsOn: ATask.dependsOn(B) A的执行依赖B B要在A前先执行
// finalizedBy: ATask.finalizedBy(B) A的执行后再执行B B要在A后执行
// mustRunAfter: ATask.mustRunAfter(B) A的执行一定要再B后面 B要在A前先执行
// 执行顺序 firstTask->taskA->secondTask
def firstTask = project.tasks.findByName("packageOverseasDebug")
def secondTask = project.tasks.findByName("assembleOverseasDebug")
if(firstTask!= null) {
taskA.mustRunAfter(firstTask)
}
if(secondTask!=null){
secondTask.dependsOn(secondTask)
}
// 执行顺序 cTask->taskB
def cTask = project.tasks.findByName("assembleOverseasDebug")
if(cTask!= null){
cTask.finalizedBy(taskB)
}
}
https://juejin.cn/post/6982379643311489032
自己编写插件
理解了Gradle的运行原理,有了问题处理的思路,明白了自己要在哪个阶段去处理,问题,剩下的操作,就是去写代码了 ,这里推荐参考Gradle 官方案例(github.com/android/gra…) 根据自己的需求,去写插件
上面的内容讲述的都是Gradle插件 ,下面要讲的是APG,Gradle Plugin
是Gradle
构建过程中使用的插件的总称,而Android Gradle Plugin
是这个总称里面的一个插件元素.AGP
配合Gradle
构建我们的应用apk
三、AGP(Android Gradle Plugin)
1、是什么
为什么要有AGP,因为AGP是官方编写的,专门针对Android应用构建流程的一个插件,这个插件的内部task是不对外暴露的,因此我们想修改一个应用的构建流程,无法通过Gradle Plugin 插件来影响其内部的task,因此需要学习APG ,使用其提供的API,来完成影响构建过程的目的
他摒弃了原有Gradle 生命周期流程(通过在 现有task的基础上,插入自定义task的操作方式影响构建结果),转而使用了自定义的生命周期,以及从工件的角度,将task的细节隐藏,开发者只要专注于构建产物,而无需关注task之间的依赖关系,在一定程度上降低了开发难度
官方指导文档:developer.android.com/studio/buil…
2、AGP生命周期
3、核心概念
重点学习对象:Variant API、工件(Artifact)和任务
工件(Artifact):Artifact 翻译过来意思是手工艺品、工件、手工制品,它就是代表着Android构建过程中的一些中间产物,如 manifest、aar、class、apk等等。
Variant API:对工件进行加工的API,其专心于产品而不是Task
,通过API访问变体对象和一些中间件,以方便用户在不接触任务的情况下影响build的行为,开发者不需求知道要修正的产品依靠于哪个Task
,也不需求知道Task
的详细完结,能够有效降低咱们开发与晋级Gradle
插件的成本。
简单理解:工件(Artifact)是核心,Variant API提供了一系列的操作方法,去加工工件,最终将工件加工成我们想要的样子
官网文档:developer.android.com/studio/buil…
4、思考
AGP的核心是工件(Artifact)
--我们可以对一个工件做哪些操作
--如何将自己的流程,插入到工件当中
5、案例
so匹配检测
/***
* 通过AGP方案实现
* Created by 11070535 at 2023/10/18
*/
private fun startPlugin(project: Project) {
if (project.plugins.findPlugin("com.android.application") == null) {
return
}
printlnWapper("SoCheckPlugin")
extension = project.extensions.create(EXTENSION_NAME, SoCheckExtension::class.java)
val androidExtension = project.extensions.getByType(AndroidComponentsExtension::class.java)
//1. 获取或创建 SoCheckExtension 对象
androidExtension.finalizeDsl {
if (extension.analysisSo) {
printlnWapper("已开启so打印")
}
}
androidExtension.onVariants { variant ->
if (!extension.analysisSo) {
return@onVariants
}
//延迟创建soTask
val taskProvider =
project.tasks.register(variant.name + "SoCheck", SoCheckTask::class.java) { task ->
task.doFirst {
printlnWapper("开始分析APK so")
}
task.builtArtifactsLoader.set(variant.artifacts.getBuiltArtifactsLoader())
task.doLast {
printlnWapper("结束分析APK so")
}
}
//将Task 结合到构建流程当中
variant.artifacts.use(taskProvider)
.wiredWithDirectories(
SoCheckTask::apkPath,
SoCheckTask::apkFolder
)
.toTransform(SingleArtifact.APK)
}
}
自定义了一个 variant.name + "SoCheck" TASK ,并将task 插入到了构建过程当中
进阶优化
延迟初始化
一个好的插件,不是一股脑把所有问题都在配置阶段给做了,对于一些过于耗时的部分,需要放到后面执行阶段去实现是最好的,
Provider<T>
延迟初始化只读变量
Property<T>
延迟初始化读写变量
TaskProvider
延迟初始化Task
这里简单理解为用到的时候在使用,,生成的Task不会立即执行,只有他被使用时,才会执行相关逻辑 具体使用可以看案例,不做过多阐述