Gradle 系列(2)手把手带你自定义 Gradle 插件

简介: Gradle 系列(2)手把手带你自定义 Gradle 插件

前言


Gradle 本质上是高度模块化的构建逻辑,便于重用并与他人分享。例如,我们熟悉的 Android 构建流程就是由 Android Gradle Plugin 引入的构建逻辑。在这篇文章里,我将带你探讨 Gradle 插件的使用方法、开发步骤和技巧总结。


1. 认识 Gradle 插件


1.1 什么是 Gradle 插件


Gradle 和 Gradle 插件是两个完全不同的概念,Gradle 提供的是一套核心的构建机制,而 Gradle 插件则是运行在这套机制上的一些具体构建逻辑,本质上和 .gradle 文件是相同。例如,我们熟悉的编译 Java 代码的能力,都是由插件提供的。


1.2 Gradle 插件的优点


虽然 Gradle 插件与 .gradle 文件本质上没有区别,.gradle 文件也能实现 Gradle 插件类似的功能。但是,Gradle 插件使用了独立模块封装构建逻辑,无论是从开发开始使用来看,Gradle 插件的整体体验都更友好。


  • 逻辑复用: 将相同的逻辑提供给多个相似项目复用,减少重复维护类似逻辑开销。当然 .gradle 文件也能做到逻辑复用,但 Gradle 插件的封装性更好;
  • 组件发布: 可以将插件发布到 Maven 仓库进行管理,其他项目可以使用插件 ID 依赖。当然 .gradle 文件也可以放到一个远程路径被其他项目引用;
  • 构建配置: Gradle 插件可以声明插件扩展来暴露可配置的属性,提供定制化能力。当然 .gradle 文件也可以做到,但实现会麻烦些。


1.3 插件的两种实现形式


Gradle 插件的核心类是 Plugin,一般使用 Project 作为泛型实参。当使用方引入插件后,其实就是调用了 Plugin#apply() 方法,我们可以把 apply() 方法理解为插件的执行入口。例如:


MyCustomGradlePlugin.groovy


public class MyCustomGradlePlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        println "Hello."
    }
}
复制代码


如果根据实现形式分类(MyCustomGradlePlugin 的代码位置),可以把 Gradle 插件分为 2 类:


  • 1、脚本插件: 脚本插件就是一个普通的脚本文件,它可以被导入都其他构建脚本中。有的朋友说脚本插件也需要使用 Plugin 接口才算脚本插件,例如:

build.gradle


apply plugin: MyCustomGradlePlugin
class MyCustomGradlePlugin implements Plugin<Project> {
    ...
}
复制代码
  • 2、二进制插件 / 对象插件: 在一个单独的插件模块中定义,其他模块通过 Plugin ID 应用插件。因为这种方式发布和复用更加友好,我们一般接触到的 Gradle 插件都是指二进制插件的形式。


1.4 应用插件的步骤


我们总结下使用二进制插件的步骤:


  • 1、将插件添加到 classpath: 将插件添加到构建脚本的 classpath 中,我们的 Gradle 构建脚本才能应用插件。这里区分本地依赖和远程依赖两种情况。

本地依赖: 指直接依赖本地插件源码,一般在调试插件的阶段是使用本地依赖的方式。


例如:


项目 build.gradle

buildscript {
    ...
    dependencies {
        // For Debug
        classpath project(":easyupload")
    }
}
复制代码

远程依赖: 指依赖已发布到 Maven 仓库的插件,一般我们都是用这种方式依赖官方或第三方实现的 Gradle 插件。例如:


项目 build.gradle


buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.3'
        // 也可以使用另一种等价语法:
        classpath group: 'com.android.tools.build ', name: 'gradle ', version: '3.5.3'
    }
    ...
}
复制代码
  • 2、使用 apply 应用插件: 在需要使用插件的 .gradle 脚本中使用 apply 应用插件,这将创建一个新的 Plugin 实例,并执行 Plugin#apply() 方法。例如:


apply plugin: 'com.android.application'
// 或者
plugins {
    // id «plugin id» [version «plugin version»] [apply «false»]
    id 'com.android.application'
}
复制代码

注意: 不支持在一个 build.gradle 中同时使用这两种语法。


1.5 特殊的 buildSrc 模块


插件模块的名称是任意的,除非使用了一个特殊的名称 “buildSrc”,buildSrc 模块是 Gradle 默认的插件模块。buildSrc 模块本质上和普通的插件模块是一样的,有一些小区别:


  • 1、buildSrc 模块会被自动识别为参与构建的模块,因此不需要在 settings.gradle 中使用 include 引入,就算引入了也会编译出错:
Build OutPut:
'buildSrc' cannot be used as a project name as it is a reserved name
复制代码
  • 2、buildSrc 模块会自动被添加到构建脚本的 classpath 中,不需要手动添加:
buildscript {
    ...
    dependencies {
        // 不需要手动添加
        // classpath project(":buildSrc")
    }
}
复制代码
  • 3、buildSrc 模块的 build.gradle 执行时机早于其他 Project:


Executing tasks: [test] 
settings.gradle:This is executed during the initialization phase.
> Configure project :buildSrc
build.gradle:buildSrc.
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy NO-SOURCE
> Task :buildSrc:pluginDescriptors UP-TO-DATE
> Task :buildSrc:processResources NO-SOURCE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :buildSrc:assemble UP-TO-DATE
> Task :buildSrc:pluginUnderTestMetadata UP-TO-DATE
> Task :buildSrc:compileTestJava NO-SOURCE
> Task :buildSrc:compileTestGroovy NO-SOURCE
> Task :buildSrc:processTestResources NO-SOURCE
> Task :buildSrc:testClasses UP-TO-DATE
> Task :buildSrc:test NO-SOURCE
> Task :buildSrc:validatePlugins UP-TO-DATE
> Task :buildSrc:check UP-TO-DATE
> Task :buildSrc:build UP-TO-DATE
...
> Configure project :
...
> Task :test
...
BUILD SUCCESSFUL in 19s
复制代码


image.png

2. 自定义 Gradle 插件的步骤


这一节我们来讲实现 Gradle 插件的具体步骤,基本步骤分为 5 步:

  • 1、初始化插件目录结构
  • 2、创建插件实现类
  • 3、配置插件实现类
  • 4、发布插件
  • 5、使用插件

2.1 初始化插件目录结构


首先,我们在 Android Studio 新建一个 Java or Kotlin Library 模块,这里以非 buildSrc 模块的情况为例:

image.png


然后,将模块 build.gradle 文件替换为以下内容:

模块 build.gradle


plugins {
    id 'groovy' // Groovy Language
    id 'org.jetbrains.kotlin.jvm' // Kotlin 
    id 'java-gradle-plugin' // Java Gradle Plugin
}
复制代码
  • groovy 插件: 使用 Groovy 语言开发必备;
  • org.jetbrains.kotlin.jvm 插件: 使用 Kotlin 语言开发必备;
  • java-gradle-plugin 插件: 用于帮助开发 Gradle 插件,会自动应用 Java Library 插件,并在 dependencies 中添加 implementation gradleApi()


最后,根据你需要的开发语言补充对应的源码文件夹,不同语言有默认的源码文件夹,你也可以在 build.gradle 文件中重新指定:

模块 build.gradle


plugins {
    id 'groovy' // Groovy Language
    id 'org.jetbrains.kotlin.jvm' // Kotlin 
    id 'java-gradle-plugin' // Java Gradle Plugin
}
sourceSets {
    main {
        groovy {
            srcDir 'src/main/groovy'
        }
        java {
            srcDir 'src/main/java'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}
复制代码

插件目录结构:

image.png


2.2 创建插件实现类


新建一个 Plugin 实现类,并重写 apply 方法中添加构建逻辑,例如:

com.pengxr.easyupload.EasyUpload.groovy


class EasyUpload implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // 构建逻辑
        println "Hello."
    }
}
复制代码


2.3 配置插件实现类

在模块 build.gradle 文件中增加以下配置,gradlePlugin 定义了插件 ID 和插件实现类的映射关系:


gradlePlugin {
    plugins {
        modularPlugin {
            // Plugin id.
            id = 'com.pengxr.easyupload'
            // Plugin implementation.
            implementationClass = 'com.pengxr.easyupload.EasyUpload'
        }
    }
}
复制代码


这其实是 Java Gradle Plugin 提供的一个简化 API,其背后会自动帮我们创建一个 [插件ID].properties 配置文件,Gradle 就是通过这个文件类进行匹配的。如果你不使用 gradlePlugin API,直接手动创建 [插件ID].properties 文件,作用是完全一样的。

image.png

要点:


  • 1、[插件ID].properties 文件名是插件 ID,用于应用插件
  • 2、[插件ID].properties 文件内容配置了插件实现类的映射,需要使用implementation-class来指定插件实习类的全限定类名


implementation-class=com.pengxr.easyupload.EasyUpload
复制代码

2.4 发布插件


我们使用 maven 插件 来发布仓库,在模块 build.gradle 文件中增加配置:

模块 build.gradle


plugins {
    id 'groovy' // Groovy Language
    id 'org.jetbrains.kotlin.jvm' // Kotlin 
    id 'java-gradle-plugin' // Java Gradle Plugin
}
gradlePlugin {
    plugins {
        modularPlugin {
            // Plugin id.
            id = 'com.pengxr.easyupload'
            // Plugin implementation.
            implementationClass = 'com.pengxr.easyupload.EasyUpload'
        }
    }
}
uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: uri('../localMavenRepository/snapshot'))
            pom.groupId = 'com.pengxr'
            pom.artifactId = 'easyupload'
            pom.version = '1.0.0'
        }
    }
}
复制代码

image.png

执行 uploadArchives 任务,会发布插件到项目根目录中的 localMavenRepository 文件夹,实际项目中通常是发布到 Nexus 私库或 Github 公共库等。不熟悉组件发布的话可以回顾:Android工程化实践:组件化发布,此处不展开。


2.5 使用插件


在项目级 build.gradle 文件中将插件添加到 classpath:

项目 build.gradle

buildscript {
    repositories {
        google()
        jcenter()
        maven { url "$rootDir/localMavenRepository/snapshot" }
        maven { url "$rootDir/localMavenRepository/release" }
    }
    dependencies {
        // For debug
        // classpath project(":easyupload")
        classpath "com.pengxr:easyupload:1.0.0"
    }
    ...
}
复制代码


在模块级 build.gradle 文件中 apply 插件:

模块 build.gradle


// '项目 build.gradle' 是在 gradlePlugin 中定义的插件 ID
apply plugin: 'com.pengxr.easyupload'
复制代码


完成以上步骤并同步项目,从 Build Output 可以看到我们的插件生效了:


Build Output:
Hello.
复制代码


到这里,自定义 Gradle 插件最基本的步骤就完成了,接下来就可以在 Plugin#apply 方法中开始你的表演。


3. 插件扩展机制


Extension 扩展是插件为外部构建脚本提供的配置项,用于支持外部自定义插件的工作方式,其实就是一个对外开放的 Java Bean 或 Groovy Bean。例如,我们熟悉的 android{} 就是 Android Gradle Plugin 提供的扩展。


当你应用一个插件时,插件定义的扩展会以 扩展名-扩展对象 键值对的形式保存在 Project 中的 ExtensionContainer 容器中。插件内外部也是通过 ExtensionContainer 访问扩展对象的。


注意事项:


  • 扩展名: 不支持在同一个 Project 上添加重复的扩展名;
  • 映射关系: 添加扩展后,不支持重新设置扩展对象;
  • DSL: 支持用 扩展名 {} DSL 的形式访问扩展对象。


3.1 基本步骤


这一节我们来讲实现 Extension 扩展的具体步骤,基本步骤分为 5 步:

  • 1、定义扩展类: 定义一个扩展配置类:

Upload.groovy


class Upload {
    String name
}
复制代码

提示: 根据 ”约定优先于配置“ 原则,尽量为配置提供默认值,或者保证配置缺省时也能正常执行。


  • 2、创建并添加扩展对象: 在 Plugin#apply() 中,将扩展对象添加到 Project 的 ExtensionContainer 容器中:

EasyUpload.groovy


class EasyUpload implements Plugin<Project> {
    // 扩展名
    public static final String UPLOAD_EXTENSION_NAME = "upload"
    @Override
    void apply(Project project) {
        // 添加扩展
        applyExtension(project)
        // 添加 Maven 发布能力
        applyMavenFeature(project)
    }
    private void applyExtension(Project project) {
        // 创建扩展,并添加到 ExtensionContainer
        project.extensions.create(UPLOAD_EXTENSION_NAME, Upload)
    }
    private void applyMavenFeature(Project project) {
        // 构建逻辑
    }
}
复制代码
  • 3、配置扩展: 使用方应用插件后,使用 扩展名 {} DSL定制插件行为:

build.gradle


apply plugin: 'com.pengxr.easyupload'
upload {
    name = "Peng"
}
复制代码
  • 4、使用扩展: 在 Plugin#apply() 中,通过 Project 的 ExtensionContainer 容器获取扩展对象,获取的代码建议封装在扩展对象内部。例如:


class EasyUpload implements Plugin<Project> {
    // 扩展名
    public static final String UPLOAD_EXTENSION_NAME = "upload"
    @Override
    void apply(Project project) {
        // 添加扩展
        applyExtension(project)
        // 添加 Maven 发布能力
        applyMavenFeature(project)
    }
    private void applyExtension(Project project) {
        // 创建扩展,并添加到 ExtensionContainer 容器
        project.extensions.create(UPLOAD_EXTENSION_NAME, Upload)
    }
    private void applyMavenFeature(Project project) {
        project.afterEvaluate {
            // 1. Upload extension
            Upload rootConfig = Upload.getConfig(project.rootProject)
            // 构建逻辑 ...
        }
    }
}
复制代码

Upload.groovy


class Upload {
    String name
    // 将获取扩展对象的代码封装为静态方法
    static Upload getConfig(Project project) {
        // 从 ExtensionContainer 容器获取扩展对象
        Upload extension = project.getExtensions().findByType(Upload.class)
        // 配置缺省的时候,赋予默认值
        if (null == extension) {
            extension = new Upload()
        }
        return extension
    }
    /**
     * 检查扩展配置是否有效
     *
     * @return true:valid
     */
    boolean checkParams() {
        return true
    }
}
复制代码


提示: ExtensionContainer#create() 支持变长参数,支持调用扩展类带参数的构造函数,例如:project.extensions.create(UPLOAD_EXTENSION_NAME, Upload,"Name") 将调用构造函数 Upload(String str)


  • 5、构建逻辑: 到这里,实现插件扩展最基本的步骤就完成了,接下来就可以在 Plugin#apply 方法中继续完成你的表演。


3.2 project.afterEvaluate 的作用


使用插件扩展一定会用到 project.afterEvaluate() 生命周期监听,这里解释一下:因为扩展配置代码的执行时机晚于 Plugin#apply() 的执行时机,所以如果不使用 project.afterEvaluate(),则在插件内部将无法正确获取配置值。


project.afterEvaluate() 会在当前 Project 配置完成后回调,这个时机扩展配置代码已经执行,在插件内部就可以正确获取配置值。


apply plugin: 'com.pengxr.easyupload'
// 执行时机晚于 apply
upload {
    name = "Peng"
}
复制代码

3.3 嵌套扩展


在扩展类中组合另一个配置类的情况,我们称为嵌套扩展,例如我们熟悉的 defaultConfig{} 就是一个嵌套扩展:


android {
    compileSdkVersion 30
    buildToolsVersion "30.0.0"
    defaultConfig {
        minSdkVersion 21
        ...
    }
    ...
}
复制代码


默认下嵌套扩展是不支持使用闭包配置,我们需要在外部扩展类中定义闭包函数。例如:

Upload.groovy


class Upload {
    // 嵌套扩展
    Maven maven
    // 嵌套扩展
    Pom pom
    // 嵌套扩展闭包函数,方法名为 maven(方法名不一定需要与属性名一致)
    void maven(Action<Maven> action) {
        action.execute(maven)
    }
    // 嵌套扩展闭包函数,方法名为 maven
    void maven(Closure closure) {
        ConfigureUtil.configure(closure, maven)
    }
    // 嵌套扩展闭包函数,方法名为 pom
    void pom(Action<Pom> action) {
        action.execute(pom)
    }
    // 嵌套扩展闭包函数,方法名为 pom
    void pom(Closure closure) {
        ConfigureUtil.configure(closure, pom)
    }
}
复制代码


使用时:

build.gradle


apply plugin: 'com.pengxr.easyupload'
upload {
    maven {
        ...
    }
}
复制代码

3.4 NamedDomainObjectContainer 命名 DSL


在 Android 工程中,你一定在 build.gradle 文件中见过以下配置:

build.gradle


android {
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            ...
        }
        // 支持任意命名
        preview {
            ...
        }
    }
}
复制代码


除了内置的 release 和 debug,我们可以在 buildType 中定义任意多个且任意名称的类型,这个是如果实现的呢?—— 这背后是因为 buildTypes 是 NamedDomainObjectContainer 类型,源码体现:

com.android.build.api.dsl.CommonExtension.kt


val buildTypes: NamedDomainObjectContainer<BuildType>
复制代码


NamedDomainObjectContainer 的作用:


NamedDomainObjectContainer 直译是命名领域对象容器,是一个支持配置不固定数量配置的容器。主要功能分为 3 点:


  • Set 容器: 支持添加多个 T 类型对象,并且不允许命名重复;
  • 命名  DSL: 支持以 DSL 的方式配置 T 类型对象,这也要求 T 类型必须带有 String name 属性,且必须带有以 String name 为参数的 public 构造函数;
  • SortSet 容器: 容器将保证元素以 name 自然顺序排序。

那么,以上配置相当于以下伪代码:

build.gradle


val buildTypes : Collections<BuildType>
BuildType release = BuildType("release")
release.minifyEnabled = false
release.proguardFiles = getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
BuildType debug = BuildType("debug")
...
BuildType preview = BuildType("preview")
...
buildTypes.add(release)
buildTypes.add(debug)
buildType.add(preview)
复制代码


NamedDomainObjectContainer 的用法:


这里介绍一下具体用法,我们仅以你熟悉的 BuildType 为例,但不等于以下为源码。

  • 1、定义类型 T: 在类型 T 中必须带有以 String name 为参数的 public 构造函数。例如:

BuildType.groovy

class BuildType {
    // 必须有 String name 属性,且不允许构造后修改
    @Nonnull
    public final String name
    // 业务参数
    boolean minifyEnabled
    BuildType(String name) {
        this.name = name
    }
}
复制代码


  • 2、定义 NamedDomainObjectContainer 属性: 在扩展类中定义一个 NamedDomainObjectContainer 类型属性。例如:

CommonExtension.grooyv


class CommonExtension {
    NamedDomainObjectContainer<BuildType> buildTypes
    CommonExtension(Project project) {
        // 通过 project.container(...) 方法创建 NamedDomainObjectContainer
        NamedDomainObjectContainer<BuildType> buildTypeObjs = project.container(BuildType)
        buildTypes = buildTypeObjs
    }
    // 嵌套扩展闭包函数,方法名为 buildTypes
    void buildTypes(Action<NamedDomainObjectContainer<BuildType>> action) {
        action.execute(buildTypes)
    }
    void buildTypes(Closure closure) {
        ConfigureUtil.configure(closure, buildTypes)
    }
}
复制代码
  • 3、创建 Extension: 按照 4.1 节介绍的步骤创建扩展。例如:
project.extensions.create("android", CommonExtension)
复制代码


到这里,就可以按照 buildTypes {} 的方式配置 BuildType 列表了。然而,你会发现每个配置项必须使用 = 进行赋值。这就有点膈应人了,有懂的大佬指导一下。


android {
    buildTypes {
        release {
            // 怎样才能省略 = 号呢?
            minifyEnabled = false
            proguardFiles = getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
复制代码



4. 插件调试

4.1 两个调试方法


在开发插件的过程一定需要调试,除了通过日志调试,我们也有断点调试的需求。这里总结两个方法:方法 1 虽然只支持调试简单执行任务,但已经能满足大部分需求,而且相对简单。而方法 2 支持命令行添加参数。


方法 1(简单): 直接提供 Android Studio 中 Gradle 面板的调试功能,即可调试插件。如下图,我们选择与插件功能相关的 Task,并右键选择 Debug 执行。

image.png


方法 2: 通过配置 IDE Configuration 以支持调试命令行任务,具体步骤:

  • 1、创建 Remote 类型 Configuration:


image.png

  • 2、执行命令:./gradlew Task -Dorg.gradle.debug=true --no-daemon (开启 Debug & 不使用守护进程),执行后命令行会进入等待状态:


  • 3、Attach Debug: 点击调试按钮,即可开始断点调试。

image.png

4.2 调试技巧


一些调试技巧:

  • 引用插件源码: 在开发阶段可以直接本地依赖插件源码,而不需要将插件发布到 Maven 仓库,只需要在 build.gradle 文件中修改配置:

项目 build.gradle


buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        // For Debug
        classpath project(":easyupload")
        // classpath "com.pengxr:easyupload:1.0.0"
    }
    ...
}
复制代码
  • 插件代码开关: 由于 Plugin#apply 中的代码在配置阶段执行,如果其中的代码有问题就会出现 Sync 报错。又因为编译插件代码需要先 Sync,只能先将工程中所有使用插件的代码注释掉,重新编译插件模块,再将注释修改回来。真麻烦!我们还是加一个开关吧,例如:


gradle.properties


ENABLED=true
复制代码

模块 build.gradle


if (ENABLED.toBoolean()) {
    apply plugin: 'com.pengxr.easyupload'
    upload {
        name = "123"
    }
}
复制代码



5. 插件开发技巧总结


  • 判断是否当前是 App 模块还是 Library 模块: 当我们开发 Android 项目相关插件时,经常需要根据插件的使用环境区分不同逻辑。例如插件应用在 App 模块和 Library 模块会采用不同逻辑。此时,我们可以用在 Plugin#apply() 中采用以下判断:


project.afterEvaluate {
    // 1. Check if apply the ‘com.android.application’ plugin
    if (!project.getPluginManager().hasPlugin("com.android.application")) {
        return
    }
}
复制代码
  • 插件开发语言: 最初,Groovy 是 Gradle 的首要语言,但随着 Java 和 Kotlin 语言的演进,这一现状有所改变。现在的趋势是:Gradle 脚本使用 Groovy 或 Kotlin 开发,而 Gradle 插件使用 Kotlin 开发。例如,我们可以发现 AGP 现在已经用 Kotlin 开发了。虽然趋势是往 Kotlin 靠,但目前存量的 Gradle 脚本 / 插件还是以 Groovy 为主。
  • Groovy 优势:社区沉淀、动态语言
  • Kotlin 优势:IDE 支持、趋势


原文: In general, a plugin implemented using Java or Kotlin, which are statically typed, will perform better than the same plugin implemented using Groovy.


6. 总结


到这里,Gradle 插件的部分就讲完了,需要 Demo 的同学可以看下我们之前实现过的小插件: EasyPrivacy。在本系列后续的文章中,也会有新的插件 Demo。关注我,带你了解更多,我们下次见。

目录
相关文章
|
Java 开发工具 Android开发
Cocos Creator 2.4.6 Android Gradle 版本升级为 6.5.1(插件4.1.0)
Cocos Creator 2.4.6 Android Gradle 版本升级为 6.5.1(插件4.1.0)
329 1
IDEA 降级gradle插件教程
IDEA 降级gradle插件教程
1380 0
IDEA 降级gradle插件教程
|
Android开发
Android Studio中修改gradle插件版本和Gradle版本
Android项目中,我们一般要设置gradle插件版本和gradle版本。 项目根目录下的build.gradle文件中,通过classpath可以指定gradle插件的版本。
|
6月前
|
Java API 项目管理
Java一分钟之-Gradle插件开发:自定义构建逻辑
【6月更文挑战第5天】Gradle插件开发详解:从入门到发布。文章介绍如何创建自定义插件,强调依赖管理、任务命名和配置阶段的理解。示例代码展示插件实现及避免常见问题的方法。最后,讨论插件的发布与共享,助你提升构建效率并贡献于开发者社区。动手实践,打造强大Gradle插件!
134 3
|
7月前
|
存储 缓存 Java
Gradle笔记 八 Gradle 插件(二)
Gradle笔记 八 Gradle 插件
152 0
|
7月前
|
Java
Gradle笔记 八 Gradle 插件(一)
Gradle笔记 八 Gradle 插件
152 0
|
IDE Java 应用服务中间件
以Gradle插件的方式为Java web项目启动Tomcat
在社区版IntelliJ IDEA除了用SmartTomcat,还有什么方式可以在可调试的情况下启动Tomcat呢,来试试com.bmuschko.tomcat插件吧
485 0
以Gradle插件的方式为Java web项目启动Tomcat
|
Java 程序员 Maven
在AndroidStudio中自定义Gradle插件
在AndroidStudio中自定义Gradle插件
在AndroidStudio中自定义Gradle插件
Gradle进阶篇(七)-AGP插件详解
前面几篇文章我们讲解了关于关于`Gradle的基础`,`Gradle生命周期`,`Gradle相关Api`的讲解,以及`Gradle自定义插件`,`Gradle Maven仓库管理`.今天这篇文章我们来讲解下`Android Gradle Plugin`相关知识。
|
Java 编译器 API
Gradle筑基篇(五)-Gradle自定义插件实战
前面几篇文章笔者对Gradle的一些基础认知,groovy基础语法,以及Gradle 项目中常用的一些api进行了讲解。今天笔者再来讲解一些关于`Gradle插件`的使用