Usando el complemento de Gradle

prefacio

El marco de Gradle solo define el proceso de construcción general y no implementa tareas de construcción específicas. Gradle es como una clase abstracta, la construcción de Java, la construcción de C ++ y la construcción de Android se implementan mediante subclases, que se entregan a los desarrolladores para que las definan. El complemento de Gradle es el punto de entrada para que los desarrolladores personalicen la lógica de compilación.

Después de dominar los conceptos básicos de Gradle, la definición de los complementos de Gradle no es difícil, sino cómo usarlos en situaciones reales y diseñar sus propias tareas.

Los complementos de Gradle que aprendí se basan básicamente en Transform api del complemento AGP combinado con instrumentación de bytecode.Este artículo presenta principalmente la definición del complemento.

Descripción general del complemento de Gradle

Para escribir un complemento de Gradle, debe implementar la interfaz del complemento. Cuando el complemento se aplica a un proyecto, Gradle creará una instancia del complemento y llamará al método Plugin.apply() del complemento. Pase el objeto del elemento como un parámetro.

La interfaz de complemento es una clase genérica, y los tipos de complementos que se pueden configurar son: Gradle, Configuración, Proyecto (tres objetos principales de Gradle) .

Correspondiente a tres archivos de configuración

Gradle—init.gradle

Configuración: configuración.gradle

Proyecto—build.gradle

Si el complemento se importa en settings.gradle, informará un error en el momento de la compilación, debido al tipo incorrecto.

El complemento Gradle actúa como un proxy para el script Gradle actual. El código escrito en el complemento se puede definir en el archivo de configuración. La diferencia es que el complemento proporciona una forma de encapsular la lógica del script y escribir la lógica en el complemento es más reutilizable.

Hay tres formas de definir un complemento. La diferencia entre los tres métodos de definición es el alcance del complemento.

  1. Definir complementos en scripts
  2. buildSrcproyecto
  3. proyecto independiente

Actualmente hay un proyecto de varios módulos con los módulos A, B y C. Escriba un complemento en el archivo build.gradle del módulo A o introduzca un archivo xxx.gradle separado. Entonces, la lógica del complemento solo tendrá efecto en el módulo A, y los módulos B y C no se verán afectados.

Si define un buildSrcproyecto, los módulos A, B, C se verán afectados por la lógica del complemento.

如果为插件创建独立项目,生成并发布一个jar包,那么就在任意项目中使用。

Plugin :hello world

演示在脚本中创建插件 并 创建任务 输入 hello world


------------------demo.gradle-------------

//创建插件
class ProjectPlugin implements Plugin<Project>{

    @Override
    void apply(Project project) {

        project.task("hello"){
            println "配置阶段 任务名称 输出: hello"
            doLast {
               println "执行阶段 hello world"
           }
        }
        println "配置阶段 输出:${project.name}"
    }
}

//应用插件
apply plugin: ProjectPlugin

--------------------任意项目下 build.gradle----------------------
apply from: "../demo.gradle"

--------------------命令行执行 查看输出----------------------
gradle  hello

定义个插件还是非常简单的,细节知识还是挺多的。

Gradle构建生命周期分三步:初始化,配置,执行。

所谓配置阶段 就是将项目内所有脚本文件执行一遍,创建任务。

执行阶段 实际是执行在配置阶段创建的任务。 每个Project中持有 TaskContainer

用Java线程池概念类比,TaskContainer 就是一个线程池。TaskContainer 中保存任务。线程池中保存Runnable

配置阶段 约等于 向线程池中添加 Runnable 。 添加任务后 在一个恰当的时机 执行提前创建的任务,就是Gradle的执行阶段。

Extension扩展(插件传参)

接下来将会看到 熟悉的 android配置原理

android {
    compileSdk 32

    defaultConfig {
        minSdk 23
        targetSdk 32
        versionCode 1
        versionName "1.0"
    }
}
------------------demo.gradle-------------

interface ProjectExtension {
    Property<String> getName()
    Property<Integer> getCode()
}

class ProjectPlugin implements Plugin<Project>{

    @Override
    void apply(Project project) {
        def user = project.extensions.create("proExt",ProjectExtension.class)
        project.task("hello"){
            println "配置阶段 任务名称 输出: hello"
            doLast {
               println "执行任务 hello world"
               println "执行任务 输出扩展信息 name:${user.name.get()}    age:${user.code.get()}"
           }
        }
        println "配置阶段 输出:${project.name}"
    }
}

apply plugin: ProjectPlugin

--------------------任意项目下 build.gradle----------------------
apply from: "../demo.gradle"

proExt {
    name = "小明"
    code = 123
}

--------------------命令行执行 查看输出----------------------
gradle  hello

定义接口,声明返回类型为 Property 的抽象方法, 定义普通JavaBean也可以达到同样的效果

需要强调的是,这两个小demo,都是在操作 void apply(Project project) {} apply方法传入的Project参数。

build.gradle中同样可以调用 extensions.create()task() 方法。

Project 代表插件依赖的项目 。Project 是个接口, 每个build.gradle都会生成一个Project对象,代表当前项目。

涉及到对于Gradle脚本的理解问题 build.gradle 约等于 Project的实现类。子类自然可以随意调用Project暴露的方法

运行下方代码,创建任务hello2,可以看到在插件中创建任务同样的效果。

注意!!! 插件也好 脚本也罢 所有的操作 本质上都是操作 Project对象

--------------------任意项目下 build.gradle----------------------

task("hello2"){
    doLast {
        println "我是 ${project.name} 的任务 hello2"
    }
}
--------------------命令行执行 查看输出----------------------
gradle  hello2

buildSrc项目

创建一个Java项目,项目名必须是 buildSrc ,不需要在settings.gradle中配置include导入,创建项目后要注释掉,不然会提示重复导入。

buildSrc 是gradle的一个保留名称,Gradle会自动识别并导入项目,把它当作插件项目运行,编译在其他子项目之前。

项目加载完毕之后,需要声明插件,

  1. 创建resources 目录
  2. 创建META-INF目录
  3. 创建gradle-plugins 目录
  4. 创建xxx.properties 配置文件,xxx会被外部识别为插件名字,比如:我们使用Android插件名称是 com.android.application ,在AGP源码中配置文件被声明为com.android.application.properties
  5. 在配置文件中声明插件实现类 implementation-class=com.example.plugin.DemoPlugin

这样一个插件就配置好了,

buildSrc项目,可以用groovy,java,kotlin实现都可,demo使用Java

Untitled.png

具体代码如下,与脚本实现插件并没有什么区别

public class DemoPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        project.getExtensions().create("demoUser", UserExtension.class);
        project.afterEvaluate(new Action<Project>() {
            @Override
            public void execute(Project project) {
                UserExtension extension = project.getExtensions().getByType(UserExtension.class);
                System.out.println(extension.toString());
            }
        });
    }
}

public class UserExtension {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "UserExtension{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

-----------任意 build.gradle-----------

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'com.example.demo' 
}

demoUser{
    name = "xixixi"
    age = 12
}

总结与参考

总体上说,单纯的写个可运行的Gradle插件还是比较简单没多少东西,难的是如何把插件机制和业务需求结合起来,emm 一直混小厂没见过啥相关案例,就不多说了。发布插件 上传maven没实践过也不多说了 有需要的同志自己研究一哈吧

开发自定义 Gradle 插件 官方文档浏览器机翻一下还是能看的

Supongo que te gusta

Origin juejin.im/post/7118260546440757279
Recomendado
Clasificación