gradle

124 阅读3分钟

1. 学习目标

  • gradle基础
  • 自定义gradle插件
  • ASM插桩

2 gradle的概念

Gradle是自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,也增加了基于Kotlin语言的kotlin-based DSL,抛弃了基于XML的各种繁琐配置。主要 通过添加一层约定和通过插件预构建的功能,可以轻松构建常见类型的项目

3 构建基础

3.1 gradle 执⾏的⽣命周期

  1. 初始化阶段
    • 执⾏ settings.gradle,确定主 project 和⼦ project
    • 解析整个工程中所有的Project,构建所有Project对应的project对象
  2. 配置阶段
    • 执⾏每个 project 的 bulid.gradle,确定出所有 task 所组成的有向⽆环图
  3. 执行阶段
    • 执行具体的task及其依赖的task
      截屏2022-10-20 16.51.35.png

各阶段的生命周期监听

1662544696677.jpg

  • 初始化阶段:gradle.settingsEvaluated和gradle.projectsLoaded。(在settings.gradle中生效)
  • 配置阶段:project.beforeEvaluate和project.afterEvaluate;gradle.beforeProject、gradle.afterProject及gradle.taskGraph.taskGraph.whenReady。
  • 执行阶段:gradle.taskGraph.beforeTask和gradle.taskGraph.afterTask

gradle 全局监听

  • gradle.addProjectEvaluationListener
  • gradle.addBuildListener
  • gradle.addListener:TaskExecutionGraphListener (任务执行图监听),TaskExecutionListener(任务执行监听),TaskExecutionListener、TaskActionListener、StandardOutputListener ...

3.2 buildSrc工程

  • 特殊的工程,gradle默认编译的工程
  • 适合封装为自定义任务或二进制插件

4 插件

4.1插件的类型

  • 脚本插件: 通过apply from 引入的.build文件
  • 二进制插件:实现Plugin接口的插件 (主要讲解)

4.2自定义二进制插件

  1. 创建工程
    • 建立buildSrc工程或者子工程
  2. 定义插件
    • 实现Plugin接口
    • 注册对于的id
  3. 实现参数配置
    • 定义,注册Extension
    • 获取和使用Extension
  4. 实现功能拓展
    • 自定义任务
    • 处理文件
  5. 发布和使用插件

5.字节码插桩

Transform方案的插入时机,在 ClassDex的过程中修改 Class 字节码。利用 Transform API,我们可以拿到所有参与构建的 Class 文件,然后可以借助ASM 等字节码编辑工具进行修改,插入自定义逻辑。 Instrumentation API 的利用Gradle提供的产物转换API TransformAction,可以注册两个属性间的转换Action,将依赖从一个状态切换到另一个状态
,AGP对其进行了封装,直接AsmClassVisitorFactory便可以进行字节码插桩。

对比TransformAPI方案,InstrumentationAPI方案的优势是

  • 不用写复杂的增量构建,内部已经处理了增量逻辑,不需要我们再手动处理
  • 构建性能大幅提升,每个transform的操作需要上一次的transofrm操作,新版本只需一次。 新方案让开发更加简洁,并且内置ASM,所以我们把开发重点放在ASM字节码的操作上 以下是官方的demo
abstract class ExamplePlugin : Plugin<Project> {

    override fun apply(project: Project) {

        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)

        androidComponents.onVariants { variant ->
            variant.transformClassesWith(ExampleClassVisitorFactory::class.java,
                                 InstrumentationScope.ALL) {
                it.writeToStdout.set(true)
            }
            variant.setAsmFramesComputationMode(FramesComputationMode.COPY_FRAMES)
        }
    }

    interface ExampleParams : InstrumentationParameters {
        @get:Input
        val writeToStdout: Property<Boolean>
    }

    abstract class ExampleClassVisitorFactory :
        AsmClassVisitorFactory<ExampleParams> {

        override fun createClassVisitor(
            classContext: ClassContext,
            nextClassVisitor: ClassVisitor
        ): ClassVisitor {
            //创建ClassVisitor
            return if (parameters.get().writeToStdout.get()) {
                TraceClassVisitor(nextClassVisitor, PrintWriter(System.out))
            } else {
                TraceClassVisitor(nextClassVisitor, PrintWriter(File("trace_out")))
            }
        }

        override fun isInstrumentable(classData: ClassData): Boolean {
            return classData.className.startsWith("com.example")
        }
    }
}

应用场景例子

  • 日志输出
  • 方法耗时统计

其他应用

  • 全埋点
  • 性能监控
  • 防止快速点击
  • 第三方库增强或修改

官网文档

参考链接