应用Gradle插件的差异

400

我不理解gradle插件块

apply plugin: 'someplugin1'
apply plugin: 'maven'

以及另一个:

plugins {
   id 'org.hidetake.ssh' version '1.1.2'
}

在第一个区块中,我们有一些插件名称。在第二个区块中是软件包和版本号。我不明白我应该在什么情况下使用第一个区块以及何时使用第二个区块。


123
使用Gradle时,准备好看到同一件事情有两种以上的方法! - Paulo Merson
56
Gradle 是构建系统中的 Perl。 - sakra
只是要注意,在第二种情况中,使用 plugins {} 时不使用包名,而是使用完全限定的插件 ID。有关详细信息,请参阅 Gradle 文档 https://docs.gradle.org/current/userguide/custom_plugins.html#sec:creating_a_plugin_id - RenatoIvancic
7个回答

327
plugins块是应用插件的较新方法,必须在Gradle插件仓库中提供。 apply方法是添加构建插件的旧方法,但更加灵活。
新的plugins方法不适用于多项目配置(subprojects, allprojects),但适用于每个子项目的构建配置。
随着功能的进展,我认为plugins配置方法将取代旧方法,但目前两种方法可以并且同时使用。

16
请注意,使用插件DSL(plugins {...})应用插件不适用于未发布到官方Gradle插件存储库的私人插件或公司插件。 这就是为什么我希望旧方法至少能在新方法支持搜索私有存储库之前继续存在的原因。 - Datz
5
根据Gradle教程(Gradle版本5.6.2)https://guides.gradle.org/creating-multi-project-builds/#add_documentation,在多项目中使用`plugins`。它使用`plugins`块并设置为`apply false将插件添加到整个项目,但不会将其添加到根项目。子项目再次使用plugins`块来添加该插件。 - yetsun
58
这真是太糟糕了,两个指令的语法和输入完全不同,而且还不兼容。使用Java和Kotlin时,Gradle绝对是最麻烦的部分。 - Christian
4
@Christian,对于使用Java来说,Maven是迄今为止最大的痛点...而我对它在Kotlin方面的支持毫不了解。 - Berin Loritsch
8
从 Gradle 6 开始,你可以在 settings.gradle 文件的 pluginManagement 块中定义仓库,以使用自己的自定义插件(甚至禁用官方的 Gradle 插件仓库)。需注意,这不会改变原意,我会尽力使翻译流畅易懂。 - Peter Headland
显示剩余4条评论

115

正如 @cjstehno 所提到的,apply plugin 是一种遗留的方法,应该避免使用。

随着插件 DSL 的引入,用户几乎没有理由使用遗留的插件应用方法。在这里记录下来,以防构建作者由于插件 DSL 当前的工作方式所限制而无法使用它。

使用新的 plugins block 方法,您可以添加插件并使用可选参数 apply 控制何时应用它:

plugins {
    id «plugin id» version «plugin version» [apply «false»]
}

在希望使用已添加但未应用的插件的情况下,仍然可以使用传统方法在plugins块中应用。例如,在主项目中添加了一个插件xyz,但尚未应用,它应该仅在子项目subPro中应用:

plugins {
  id "xyz" version "1.0.0" apply false
}

subprojects { subproject ->
    if (subproject.name == "subPro") {
        apply plugin: 'xyz'
    }
}

请注意,您不再需要版本号。除非您使用javascala等Core Gradle插件之一,否则在plugins块中需要版本号。

我花了些时间理解其中的区别,因为我尝试创建一个Spring Boot应用程序,这就是为什么过了一段时间后我又来回答这个问题。以下示例展示如何使用Spring Boot插件,对我帮助很大:

目前应该使用什么:

plugins {
  id "org.springframework.boot" version "2.0.1.RELEASE"
}

在 Gradle 2.1 之前使用的是什么:

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE"
  }
}

apply plugin: "org.springframework.boot"

6
这样会给人留下错误的印象。不能简单地将apply plugin xxx转换为plugins { id xxx }(我尝试过,但不起作用)。 - Christian
1
我认为答案和引用的文档已经很清楚地说明了这一点。这取决于你的情况。你可以提供更多关于你的情况的信息,或者在另一个问题中发布这个问题。 - Mousa
在我的情况下,我成功地从旧方法转换到了新方法,对于插件“org.openapi.generator”,只需删除buildscript块和旧的apply plugin行,并在plugins块内使用id和version,它可以很好地工作。 - raspacorp
2
如果你想将 apply plugin 转换为 plugins { id xxx },你可以在 https://plugins.gradle.org/ 找到你的插件,这将给你正确的 id,通常与使用 apply plugin 的限定名称略有不同。 - Monkey Supersonic

17
这是使用Gradle插件的两种不同方式。

使用apply plugin的方式

首先在根目录下的build.gradle文件中解决所需的插件。
示例:

buildscript {
        repositories {
            // other repositories...
            mavenCentral()
        }
        dependencies {
            // other plugins...
            classpath 'com.google.dagger:hilt-android-gradle-plugin:2.44'
    }

然后在Gradle模块的build.gradle中应用插件。
示例:
apply plugin: 'com.android.application'
apply plugin: 'com.google.dagger.hilt.android'

插件方式

在您的根build.gradle文件中结合resolve和apply。
示例:

plugins {
    // other plugins...
    id 'com.google.dagger.hilt.android' version '2.44' apply false
}

然后在Gradle模块的build.gradle中应用插件。
示例:
plugins {
    // other plugins...
    id 'com.android.application'
    id 'com.google.dagger.hilt.android'
}

android {
    // ...
}

2
我正在将我的Gradle文件从旧的“apply plugin”迁移到新的“plugins {}”方法,并且我在查找给定依赖项的正确ID方面遇到了问题。是否有一个通用的方法?我目前卡在实现来自https://github.com/google/play-services-plugins/blob/master/oss-licenses-plugin/README.md的依赖项上。有关如何在插件块中找到其ID的任何建议吗? - Koger

8

现在(在 Gradle 6 中),您可以在不使用构建脚本的情况下为插件指定仓库名称。 在 settings.gradle 文件中,我们可以添加插件 pluginManagement。

pluginManagement {
    repositories {
        maven {
            url '../maven-repo'
        }
        gradlePluginPortal()
        ivy {
            url '../ivy-repo'
        }
    }
}

参考:https://docs.gradle.org/current/userguide/plugins.html#sec:custom_plugin_repositories

这个链接是关于Gradle自定义插件仓库的文档。

7
我要在已有的内容上加入一点小变化。Gradle引入了插件块的概念,作为一种加速和优化构建过程的技术手段。以下是Gradle文档中的说明:

这种向项目添加插件的方式不仅仅是更方便的语法。插件DSL以一种允许Gradle非常早和非常快地确定正在使用的插件的方式进行处理。这使得Gradle能够做出智能决策,例如:
优化加载和重用插件类。
为编辑器提供有关buildscript中潜在属性和值的详细信息,以获得编辑帮助。
这要求以一种Gradle可以轻松快速提取的方式指定插件,然后再执行其余的构建脚本。它还要求使用的插件定义相对静态。

这不仅仅是处理插件的新方法,而且是改进构建过程和/或用户编辑体验的一种方式。
为了让它正常工作,需要在构建的顶部指定,但如果包含一个 buildscript 块,则还需要在其后指定。为什么呢?因为构建脚本中的代码是按照编写顺序进行评估的。必须在插件块被评估之前评估 buildscript 块。请记住,buildscript 块是关于设置插件环境的。因此,插件块必须在 buildscript 块之后指定。
新的插件块不仅指定项目使用的插件,还指定插件是否应用。默认情况下,插件块中的所有插件都会自动应用,除非明确声明不应用(即在插件声明后添加“apply false”)。
那么为什么要声明插件而不应用它呢?我能想到两个主要原因:
1. 为了声明所需使用的插件版本。声明插件后,插件现在位于“classpath”上。一旦插件在 classpath 上,以后再应用它时就不再需要指定插件的版本。在多项目构建中,这使得支持构建脚本变得更容易。(即只有一个地方指定插件版本。)

2.) 有时候,你可能会有一个插件,需要在应用之前定义某些内容。在这种情况下,你可以在 plugins 块中声明一个插件,并推迟插件的应用,直到你定义了插件所需的输入内容。例如,我有一个自定义插件,它查找名为“mavenResource”的配置。在 dependencies 块中,我添加了一个依赖项,如:“mavenResource(maven_coordinate)”。该插件将查找 mavenResource 配置中包含的所有依赖项,并将相关的 maven artifact 复制到项目的“src/main/resources”目录中。正如你所看到的,我不想在添加 mavenResource 配置和定义 mavenResource 依赖项之前应用该插件。因此,我在 plugins 块中定义我的自定义插件,并在项目依赖项被定义后应用它。因此,认为应用插件是老式和错误的概念是一种误解。

有些人可能会想知道应用插件是什么意思。其实很简单,就是调用插件的 apply 函数并将 Gradle 项目对象传递给正在应用插件的项目。从那时起,插件所做的一切完全取决于插件本身。通常,apply 函数通常会创建一些 Gradle 任务并将它们添加到 Gradle 构建任务依赖图中。当 Gradle 开始执行阶段时,这些任务将在构建过程中的适当时间执行。插件 apply 函数还可以做一些事情,比如将一些工作推迟到 afterEvaluate 之后。这是一种允许构建脚本中的其他内容设置的方法,即使它们在 buildscript 中稍后定义也可以。那么,你可能会问为什么我没有在自定义插件中使用这个技巧。我观察到,在根项目完成评估后,下一个子项目开始处理。在我的情况下,我需要在下一个子项目开始之前添加资源。因此,存在竞争条件,我通过不使用 afterEvaluate 技术并在设置完成所需的内容后专门应用插件来避免了这种情况。

3
我想指出的是,并不需要将插件发布到远程才能使用它!同样可以是未发布的本地可用插件(无论是常规插件还是其他插件)。
如果想要引用这样一个未发布的本地可用插件,您需要在所需组件/构建中包含其所谓的“构建”(通过settings.gradle(.kts)文件进行标识),如下所示:
pluginManagement {
    includeBuild '<path-to-the-plugin-dir-containing-the-settings-file>'
}

完成上述步骤后,可以通过pluginIdplugins {} DSL块中使用本地插件。

2
如果插件需要一个版本,则更安全的做法是将版本号放在settings.gradle文件中的pluginManagement块中,而不是plugins块中。
“更安全”是指您不会遇到像“插件请求已经在类路径上的插件必须不包括版本”的错误。如果您将一个项目includeFlat 包含到另一个使用相同插件的项目中,并且您的插件版本在plugins块中,那么这种情况可能会发生。
因此,与其这样:
plugins {
    id 'pl.allegro.tech.build.axion-release' version '1.10.3'
}

做:
plugins {
  id 'pl.allegro.tech.build.axion-release'
}

然后在你的 settings.gradle 文件中:
pluginManagement {
    plugins {
        id 'pl.allegro.tech.build.axion-release' version '1.10.3'
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接