从基础开始:Gradle插件开发的简易指南

604 阅读4分钟

截屏2024-07-24 下午4.06.47.png

前言

这篇文章讲解了 Gradle 的工作流程,Gradle 中的一些重要 API,以及编写一个最简单的 Gradle 插件,和 Gradle Plugin 有哪些应用场景

最后还需要了解 Transform 的变动,最新版本的 AGP 已经将这个类废弃了,我们该怎样做适配呢?(适配,插件开发-渠道包和函数插桩单独写博客,太长了)

Gradle 不是魔法

Gradle 作为 Android 的构建工具,在我们按下 Android Studio 的 Build 按钮时,会将项目中的资源文件和代码文件进行处理,执行混淆,生成 APK 最后对其进行签名

上面的这些一系列操作,可以分为一个个 Task,所有 Task 执行完成后最终产出了一个可以发布的应用文件,是不是很神奇?

但它并不是“魔法”,也是由代码组成,并且在学习了 Gradle 基础知识后,也可以在编译过程中加上我们自己的操作,比如函数插桩检测耗时,生成一个路由表(组件化开发),或者多渠道打包

那 Gradle 的基础知识有哪些是必须要了解的呢?

  • grovvy / kts ,相比起 C 这两种更接近 Java,上手相对容易很多(不是说 C 也能写 gradle)
  • Gradle 的工作流程
  • Task,Transform,Extension

Gradle 基础知识

groovy

  • 一门动态语言,特点就是调用了一个不存在的方法也不报错 (😓)
  • 闭包也是它的另一个特点,我们经常在 gradle 文件中看到 android{ xxx true} 这样的语句,里面实则是方法调用,这样让方法调用看起来像一个个配置文件
Task

前面说到 Grade 是由一个个 Task 组成的

  • doFirst,doLast 来精细化控制,比如在 doFirst 中初始化一些环境配置,doLast 中释放资源

    task exampleTask {
        doFirst {
            println '这个被第一个执行'
        }
        doLast {
            println '这个在最后被执行'
        }
        doFirst {
            println '这个在第二个被执行'
        }
    
        println '执行当前任务'
    }
    
  • depondsOn :如果一个任务依赖其他任务执行,在 Gradle 构建任务树时,会在执行 A 时先执行 B Task

    task A {
    	depondsOn B 
        println '执行当前任务'
    }
    

Gradle 的工作流程

回想一下,当我们按下构建 Apk 的按钮后,Android Stduio 内部做了什么呢?

  • 配置

    1. 检查任务对象

    2. 检查每个任务间的依赖关系

    3. 构建一个任务依赖树

      还记得上面提到的 Task depondsOn 语句吗,在这里发挥了作用

  • 执行

    1. 根据上一步确定的 Task 的步骤执行
    2. 确保当前 Task 执行前,其依赖的 Task 已经执行完成
  • 构建完成

    输出报告:任务的执行时间,成功和失败的任务总结,这里可以看到 Build Failed 是哪些地方出错了

Gradle 的项目结构

字丑勿怪 😂

截屏2024-07-23 下午2.43.40.png

Gradle Transform

AGP(Android Gradle plugin) 提供的一个工具,在打包之前,将编译结果开放,允许开发者修改

可以实现什么:

  • AOP,可以插桩增加统计函数运行耗时的代码,这里可以统计处理,相比较常规的方法,这里简洁很多
  • 这里 Transform 只是提供了一个操作入口,具体的修改删除需要借助 ASM,JavaAsisat,ASM 有个 Visitor 类,封装了对于字节码的操作,降低了使用成本

编写一个简单的插件

首先自定义一个 Plugin 一般是为了给其他项目用的(复用),使用者只需要在 .gradle 中 apply xxPluginName ,就可以用上了,下面来一步步实现最简单的 plugin 插件

最简单的 Gradle plugin 就是调用 println 打印一句话了,有几个步骤

新建一个项目

在 AS 中新建一个 Android 项目,我这里叫 GradlePlugin,然后新建一个 java lib 的 moudle,注意这个 moudle 的名字必须是 buildSrc,因为对于 Gradle 来说一个名为 buildSrc 的项目就是插件项目

此时尝试编译会遇到报错,去 setting.gradle 中将 include buildSrc 删掉,再尝试编译就会看到一个 buildSrc 的文件夹了

截屏2024-07-24 上午10.26.16.png

此时 buildSrc.gradle 文件长这样,实际上图中的 plugins 可以删掉,也是能正常编译的

截屏2024-07-24 上午10.28.30.png

实现 plugin 类

// groovy 文件,新建一个 Java Class 可以手动改为 groovy 
import org.gradle.api.Plugin;
import org.gradle.api.Project;

class KGradlePlugin implements Plugin<Project> {

    @Override
    public void apply(Project target) {
        target.afterEvaluate{
            println "k gradle plugin"
        }
    }
}

插件的配置

走到这一步,如果直接在 app moudle 下 apply 插件,Gradle 是无法找到的,这里还需要一点配置

在 buildSrc 模块的 main 目录下,分别创建如下目录,resources>META-INF>gradle-plugins>xxx.properties (文件)

截屏2024-07-24 下午2.43.21.png

在新建的 properties 文件中指定插件类的路径

截屏2024-07-24 下午2.43.56.png

最后在 app 模块的 gradle 中配置一下

截屏2024-07-24 下午2.47.26.png

尝试运行

截屏2024-07-24 下午2.47.45.png

应用场景

  • 函数插桩检测耗时
  • 多渠道打包
  • etc...

相关链接