Gradle插件在项目中的应用方式

1,110 阅读3分钟

Gradle基础概念

  • projects ( 项目 ):每一个构建都是由一个或多个 projects 构成的,安卓工程每个module工程就是一个project,对应的是module里面的build.gradle文件

project.png

  • tasks ( 任务 ):每一个 project 是由一个或多个 tasks 构成的. 一个 task 代表一些更加细化的构建

task.png

Gradle 扩展

如上图project,project是实现了ExtensionAware的。ExtensionAware的getExtensions方法返回了一个ExtensionContainer,也就是一个可以扩展容器。通过ExtensionContainer我们可以去创建扩展。

org.gradle.api.tasks.TaskContainer接口:
//查找task
findByPath(path: String): Task
getByPath(path: String): Task
getByName(name: String): Task
withType(type: Class): TaskCollection
matching(condition: Closure): TaskCollection

//创建task
create(name: String): Task
create(name: String, configure: Closure): Task 
create(name: String, type: Class): Task
create(options: Map<String, ?>): Task
create(options: Map<String, ?>, configure: Closure): Task

ExtensionAware.png

ExtensionContainer.png

extuse.png

按照文档,我们来试试

set.png

注释掉配置里面的内容,我们再看看运行打印结果

notset.png 从上图可以看出,如果我们没有配置,就会使用默认的,这种配置的写法是不是似曾相识,譬如我们经常要改动的android{}里面的版本号之类的,android 它就是一个 Extension,看看源码就知道android 实际就是 AppExtension 这个类。所以 android 能配置什么属性就可以在 AppExtension查找即可。

/**
 * Gradle plugin class for 'application' projects.
 */
public class AppPlugin extends BasePlugin implements Plugin<Project> {
    
    protected BaseExtension createExtension(
            @NonNull Project project,
            @NonNull Instantiator instantiator,
            @NonNull AndroidBuilder androidBuilder,
            @NonNull SdkHandler sdkHandler,
            @NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer,
            @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer,
            @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer,
            @NonNull ExtraModelInfo extraModelInfo) {
        return project.getExtensions()
                .create(
                        "android",//"android" 就是 Extension 的名字
                        AppExtension.class,
                        project,
                        instantiator,
                        androidBuilder,
                        sdkHandler,
                        buildTypeContainer,
                        productFlavorContainer,
                        signingConfigContainer,
                        extraModelInfo);
    }


Gradle 本地脚本插件

有时候我们不希望很多把很多gradle脚本写在build.gradle里面,通过apply就可以依赖本地其他gradle文件,就如同java里面import一样

localgradle.png

Gradle 远程脚本插件

其实和本地插件一样,只不过是依赖的远程http的url地址。有时候有些脚本我们需要动态的改变的时候使用这种方法,譬如我们的依赖组件的版本号统一管理,所有同一个版本发布的组件引用同一个分支的远程gradle文件。

gitplugin.png

remoteplugin.png

Gradle 二进制插件

Gradle插件主要是实现Plugin接口apply方法,下面是之前我写的一个检测项目中图片是否全部是webp的插件,因为webp体积小,用于体积优化的任务插件

  1. 在项目工程的根目录下创建buildSrc目录,这个名字不能错,必须是buildSrc。创建完之后,rebuild一下工程,会在buildSrc下生成一些目录
  2. 在buildSrc目录下创建build.gradle.kts文件,用kotlin写插件

kotlingradle.png

plugins {
    `kotlin-dsl`
}
repositories {
    jcenter()
}
  1. 在buildSrc目录下创建src/main/kotlin目录,目录名字一定不要错!!!,然后编写插件

taskImpl.png 4. 在 main 目录下新建 resources 目录,然后在 resources 目录里面再新建 META-INF 目录,再在 META-INF 里面新建 gradle-plugins 目录。最后在 gradle-plugins 目录里面新建 properties 文件,注意这个文件的命名,你可以随意取名,但是后面使用这个插件的时候,会用到这个名字。比如,你取名为com.example.harry.properties,那么这个插件的id就是com.example.harry

resource.png 5. 在app中进行引用

taskrun.png

  • 我们还可以通过另一种方式来生成插件
gradlePlugin {
    plugins {
        create("HarryPlugin2") {
            //插件id,用于引用插件,如:apply plugin: 'id'
            id = "com.example.harry2"
            //指定插件的实现类
            implementationClass = "com.example.harry.HarryPlugin2"
        }
    }
}

plugin2.png

  • 我们还可以通过这个buildSrc包来进行依赖管理

deps.png

depimpl.png

独立插件maven的发布

  • 直接新建一个module,不需要以buildSrc命令。新建module默认的gradle里面内容删除掉,添加maven依赖,编写插件后即可发布本地maven仓库

maven.png

发布完成后即可在项目中引用 mavenapply.png

上面是使用的本地仓库,如果有maven服务器,将url替换成远程maven即可。maven服务搭建请点击这里

文中代码地址