0530-3433334

网站建设 APP开发 小程序

知识

分享你我感悟

您当前位置>首页 >> 知识 >> 软件开发

第8篇——插件开发指南(二十五)

发表时间:2023-09-20 17:00:29

文章来源:炫佑科技

浏览次数:155

菏泽炫佑科技

第8篇——插件开发指南(二十五)

本文经作者许可发表。

前言

插件开发占据了一定比例的高级知识,尤其是性能优化领域,基本都覆盖了,也和我们日常的编译打包密切相关。 另外,很多招聘要求明确要求有插件开发经验。 所以即使大多数人在日常开发中可能不会使用插件开发,但仍然向往。 本文为您带来该系列的第8篇文章——插件开发指南,希望能给您带来收益。

什么是插件

() 是一种用于扩展和自定义构建系统功能的机制。 它是一个强大的构建自动化工具,用于构建和管理各种类型的项目,从简单的 Java 应用程序到复杂的多模块企业级项目。 插件提供了灵活性,允许开发人员根据特定需求添加自定义行为和功能。

插件可以执行各种任务,包括编译代码、执行测试、打包文件、生成文档等等。 插件可以访问和操作构建模型,例如项目、任务、依赖项等,以实现构建过程的控制和定制。

提供了丰富的插件生态系统,可以使用现有的官方插件或第三方插件来增强构建过程。 很多流行的框架和工具,比如,Boot等,都有相应的插件,使得与这些技术栈的集成变得更加简单和高效。

比如我们熟悉的插件com..:

plugins {
    id 'com.android.application'
}

通过编写自己的插件,您可以自定义和扩展构建系统以满足特定项目的需求。 您可以在插件中定义自定义任务、配置扩展、操作项目属性、应用其他插件等。 插件使构建过程可控、可定制,从而提高开发效率。

为什么要写插件?

编写插件的意义:

封装,提取具体逻辑,项目只需要运行插件即可,不需要放在某个build中。 文件,这会降低构建的可读性。

复用,提取通用逻辑软件开发,使用时只需应用插件即可。 不需要一遍又一遍的复制第8篇——插件开发指南(二十五),也可以提供给其他项目使用;

定制:如果在编译时需要做一些插桩、Hook等定制操作,还需要使用编译插件。

插件写在哪里?

上面我们介绍了Task,也提到Task写在哪里,但是写在哪里呢?

插件可以写在3个地方:

和Task一样,它是写在build中的。 文件且范围是当前的;

写进去,范围是当前项目所拥有的;

写在一个单独的项目中,发布后可以供所有项目使用。

根据自己的需要,结合插件作用域,可以写在不同的位置。

自定义插件

开发软件需要学什么专业_开发软件的基本流程_软件开发

编写插件其实很简单。 你只需要实现接口并实现唯一的apply方法。

我们直接在build中写就可以了。 文件:

class YechaoaPlugin implements Plugin<Project{

    @Override
    void apply(Project project) {
        println("这是插件:${this.class.name}")
    }
}

apply plugin: YechaoaPlugin
//apply(plugin: YechaoaPlugin)

这实际上是一个内联类。

编写后不要忘记应用依赖项。 第9行的apply方法是被调用接口的apply()方法,参数是一个map,用于映射ID。

同步输出:

Configure project :app
这是插件:YechaoaPlugin
...

上一篇文章对Task的详细讲解中提到,Task是 中的一个方法,所以我们需要通过它来创建一个Task。 示例中的类实现了接口并实现了唯一的apply方法,而apply方法提供了一个对象,所以我们也可以在其中创建一个Task。

class YechaoaPlugin implements Plugin<Project{

    @Override
    void apply(Project project) {
        println("这是插件:${this.class.name}")
        project.task("YechaoaPluginTask") { task ->
            task.doLast {
                println("这是插件:${this.class.name},它创建了一个Task:${task.name}")
            }
        }
    }
}

如上,我们在 . 此时sync不会执行Task中的打印。 我们必须单独执行任务。

实施:

./gradlew YechaoaPluginTask

输出:

Task :app:YechaoaPluginTask
这是插件:YechaoaPlugin,它创建了一个TaskYechaoaPluginTask

OK,*基本的写法就是这么简单。

结合上面两个输出,无论是简单的打印进去,还是创建一个Task进去,当我们依赖一个插件的时候,也就是apply:,这个apply就会把插件放进去,同样的,同时,这个apply也是在编译阶段执行接口的apply()方法,所以sync执行构建后会有输出,执行的Task也在有向无环图中。

自定义插件扩展

在本系列的第二章中,我们分析了 { } 闭包是如何从源代码中得出的。 { } 闭包是我们非常熟悉的配置。 通过DSL,我们经常在里面进行配置等。

在自定义插件的时候,经常会需要这种自定义配置。 通过这些自定义配置,我们的插件可以提供更丰富的功能。 这些配置是通过扩展插件提供的。

6.1. 定义扩展对象

interface YechaoaPluginExtension{
    Property<String> getTitle()
}

它可以是一个接口或一个类。

6.2. 添加扩展并使用它们

开发软件需要学什么专业_开发软件的基本流程_软件开发

class YechaoaPlugin implements Plugin<Project{

    @Override
    void apply(Project project) {
        println("这是插件:${this.class.name}")
        def extension = project.extensions.create("yechaoa", YechaoaPluginExtension)
        project.task("YechaoaPluginTask") { task ->
            task.doLast {
                println("这是插件${this.class.name},它创建了一个Task:${task.name}")
                println(extension.title.get())
            }
        }
    }
}

..() 方法接收两个参数:

**个是名称,例如;

第二种是扩展对象,然后返回扩展对象。 通过该扩展对象的方法可以获取定制的配置参数。

6.3. 配置参数

yechaoa.massage = "【Gradle-8】Gradle插件开发指南"

一个配置可以直接省略,也可以这样写:

yechaoa {
      massage = "【Gradle-8】Gradle插件开发指南"
}

如果没有设置配置参数,也提供默认值设置:

extension.title.convention("默认配置title")

如果是类对象,则定义/。

如果有多个配置怎么写? 只需扩展多个配置属性即可。

6.4. 嵌套扩展

如下,{ } 还包含 { }

android {
    namespace 'com.yechaoa.gradlex'
    compileSdk 32

    defaultConfig {
        applicationId "com.yechaoa.gradlex"
        ...
    }
}

嵌套扩展其实很简单,就像套娃一样。

上面我们使用接口来定义扩展属性。 我们改变一下写法,用类对象来定义。

6.4.1. 定义扩展

class YechaoaPluginExtension {
    String title
    int chapter
    SubExtension subExtension

    YechaoaPluginExtension(Project project) {
        subExtension = project.extensions.create('sub', SubExtension.class)
    }
}
class SubExtension {
    String author
}

再定义一个类,并在实例化时将其添加到 on 中。

如果你想嵌套类,那没问题。 它们必须是内联类,否则编译器将无法识别它们。

6.4.2. 获取扩展属性

class YechaoaPlugin implements Plugin<Project{

    @Override
    void apply(Project project) {
        println("这是插件:${this.class.name}")
        def extension = project.extensions.create("yechaoa", YechaoaPluginExtension)
        // 设置默认值 可以定义set()方法 然后在这里set
        project.task("YechaoaPluginTask") { task ->
            task.doLast {
                println("这是插件${this.class.name},它创建了一个Task:${task.name}")
                println("title = ${extension.title}")
                println("chapter = ${extension.chapter}")
                println("author = ${extension.subExtension.author}")
            }
        }
    }
}

与上面接口定义的例子相比,缺少了对象的.get(),并且也去掉了默认值的设置。 如果你愿意,只需在类对象中定义/方法即可,其他逻辑保持不变。

6.4.3. 使用

yechaoa {
    title = "【Gradle-8】Gradle插件开发指南"
    chapter = 8
    sub {
        author = "yechaoa"
    }
}

在闭包配置中,有一个额外的 sub{ } 闭包,它是在我们的 on 类中定义的。

6.4.4. 执行

./gradlew YechaoaPluginTask

6.4.5。 输出

> Task :app:YechaoaPluginTask
title = 【Gradle-8】Gradle插件开发指南
chapter = 8
author = yechaoa

6.4.6。 完整代码

class YechaoaPluginExtension {
    String title
    int chapter
    SubExtension subExtension

    YechaoaPluginExtension(Project project) {
        subExtension = project.extensions.create('sub', SubExtension.class)
    }
}
class SubExtension {
    String author
}

class YechaoaPlugin implements Plugin<Project{

    @Override
    void apply(Project project) {
        println("这是插件:${this.class.name}")
        def extension = project.extensions.create("yechaoa", YechaoaPluginExtension)
        // 设置默认值 可以定义set()方法 然后在这里set
        project.task("YechaoaPluginTask") { task ->
            task.doLast {
                println("这是插件${this.class.name},它创建了一个Task:${task.name}")
                println("title = ${extension.title}")
                println("chapter = ${extension.chapter}")
                println("author = ${extension.subExtension.author}")
            }
        }
    }
}

apply plugin: YechaoaPlugin

yechaoa {
    title = "【Gradle-8】Gradle插件开发指南"
    chapter = 8
    sub {
        author = "yechaoa"
    }
}

现在 { } 这个配置是不是很熟悉:

yechaoa {
    title = "【Gradle-8】Gradle插件开发指南"
    chapter = 8
    sub {
        author = "yechaoa"
    }
}

和{}一样吗:

android {
    namespace 'com.yechaoa.gradlex'
    compileSdk 32

    defaultConfig {
        applicationId "com.yechaoa.gradlex"
        ...
    }
}

写在一个单独的项目中

我们上面的内容都写在 build 中了。 文件,但一般在实际项目中,为了更好的复用,通常会写在单独的项目中或者单独的项目中。

构建中的写法还是有一些区别的。 文件并写入一个单独的项目中。 我们来看看在单独的项目中怎么写(等于)。

让我们简单一点,只需编写一个打印项目中所有依赖项的程序即可。

7.1. 新的

新建一个名称,类型选择Java或以下。

创建后会有默认的文件目录,多余的文件可以删除。

开发软件的基本流程_软件开发_开发软件需要学什么专业

我们可以看到主文件夹下有一个java文件夹。 你可以用java写,也可以使用和学习。 无论你喜欢什么,你都可以在主文件下创建一个与语言相对应的新文件夹界面,例如文件夹。

7.2. 创建一个新文件并添加依赖项。 7.2.1. 创建一个新类。

创建一个新类:

但是这个时候你还是写不出来,因为你没有依赖相关的API。

7.2.2. 添加依赖项

在6.4及以后版本中,不需要添加()来配置依赖。 直接用java--就可以完成,它会自动将java和()依赖添加到项目中。

并且您不需要在 src/main//META-INF/-/xxx 中配置您的 -class。 像以前一样。 只需配置 { } 即可自动生成 META-INF 描述文件。

依赖于 >build.xml 中的插件。 文件:

plugins {
    id 'java-gradle-plugin'
}

配置如下:

gradlePlugin{
    plugins{
        DependenciesPlugin{
            id = 'com.yechaoa.plugin.dependencies'
            implementationClass = 'com.yechaoa.plugin.DependenciesPlugin'
        }
    }
}

6.4之前:

implementation-class=com.yechaoa.plugin.DependenciesPlugin

因为以前这些文件夹和配置都是手动的,非常繁琐。 相比之下,现在就过得愉快多了。

7.3. 写作

package com.yechaoa.plugin;


import org.gradle.api.Plugin;
import org.gradle.api.Project;

/**
 * GitHub : https://github.com/yechaoa
 * CSDN : http://blog.csdn.net/yechaoa
 * 


 * Created by yechao on 2023/8/8.
 * Describe :
 */
class DependenciesPlugin implements Plugin<Project{

    @Override
    public void apply(Project project) {
        System.out.println(">>>>>>>>  " + this.getClass().getName());
    }
}

创建一个新类来实现该接口;

在 apply 方法中实现您自己的逻辑,如本示例所示。

至此,基本原型已经就位。

使用以下命令添加依赖项:

apply plugin: 'com.yechaoa.plugin.dependencies'

开发软件的基本流程_开发软件需要学什么专业_软件开发

但现在它不能在外部项目中使用。 如果直接引用this的话,是找不到的(未找到)。

Plugin with id 'com.yechaoa.plugin.dependencies' not found.

因为这是在一个单独的项目中写的,准确的说是和其他项目没有任何关系。 如果你想找到这个插件,你就必须发布它。

7.4. 本地发布

本地发布比远程发布简单得多。 远程发布虽然不难,只是比较麻烦。

7.4.1. Maven 插件

首先,比较常用的仓库是maven。 在>构建中。 文件,首先依赖maven发布的插件'maven-'。

plugins {
    id 'maven-publish'
}

dependencies {
    implementation 'com.android.tools.build:gradle:7.3.0'
}

7.4.2. 发布配置

添加发布配置:

group 'com.yechaoa.plugin'
version '1.0.0'

publishing {
    // 配置Plugin GAV
    publications {
        maven(MavenPublication) {
            groupId = group
            artifactId = 'dependencies'
            version = version

            from components.java
        }
    }
    // 配置仓库地址
    repositories {
        maven {
            url layout.buildDirectory.dir("maven-repo")
        }
    }
}

7.4.3. 执行发布操作

./gradlew publish

或者点击右侧可视化面板中的Run:

7.4.4. 生成产品

好了,现在build文件夹下多了一个带有本地发布配置的maven-repo文件夹。

可以再次确认maven元数据和pom文件:

<metadata>
  <groupId>com.yechaoa.plugingroupId>
  <artifactId>dependenciesartifactId>
  <versioning>
    <latest>1.0.0latest>
    <release>1.0.0release>
    <versions>
      <version>1.0.0version>
    versions>
    <lastUpdated>20230809154815lastUpdated>
  versioning>
metadata>

7.5。 使用

好了,本地发布完成。 如果要使用这个插件的话,流程和我们正常依赖插件是一样的。

三个步骤:

在.xml文件中配置插件仓库地址文件。

pluginManagement {
    repositories {
        // ...
        maven {
            url './maven-repo'
        }
    }
}

炫佑科技专注互联网开发小程序开发-app开发-软件开发-网站制作等