[Gradle翻译]是时候抛弃buildcript块了

324 阅读4分钟

本文由 简悦SimpRead 转码, 原文地址 stefma.medium.com

构建脚本块

image.png 和你在一起是一段有趣的旅程。但现在是说再见的时候了 👋

构建脚本块

每个使用Gradle作为底层构建工具的开发者都知道buildscript块。或者至少知道如何使用它。在我深入探讨为什么我们应该摆脱它之前,我想解释一下它到底是什么以及它的作用。

buildscript {
  repositories {
    google()
    jcenter()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:3.1.1'
  }
}

上面的build.gradle文件在你每次创建新项目(不含Kotlin)时都会由Android Studio自动生成,并存在于你项目的顶层目录中。

但这个块是做什么的呢?基本上它定义了构建本身所需的依赖关系。或者换句话说。它定义了构建你的应用程序(无论你的 "应用程序 "是什么(Android应用程序、Gradle插件、Swift桌面应用程序......))所需的依赖。

在我们的安卓例子中,我们必须定义安卓Gradle插件的依赖关系,以帮助我们构建一个APK。

// project/build.gradle
buildscript {
  repositories {
    google()
    jcenter()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:3.1.1'
  }
}
// project/app/build.gradle.kts
apply {
  plugin("com.android.application")
}

既然我们知道它的作用,为什么要抛弃它呢?🤔

好吧,我并没有说我们不再需要它背后的逻辑(应用构建所需的依赖关系)。我更想说的是,我们必须用一些 "新 "东西来取代传统的buildscript

插件块的崛起

这个 "新 "的plugins块其实并不新鲜。它已经在Gradle 2.1中被引入。在那时,它显然没有得到那么多的关注。

然而。插件块容易阅读和使用。

// project/app/build.gradle.kts
plugins {
  id("org.gradle.java")
  kotlin("jvm") version "1.2.40"
}

你可能注意到,这只是一个文件,而不是两个?

但也有一些 "限制"。默认情况下,plugin块只能解决属于以下两种情况的插件。

  • 核心插件(由Gradle自己提供)。例如,这些是: org.gradle.java, org.gradle.groovy, org.gradle.java-gradle-plugin等等...
  • 发布到Gradle Plugin Portal

不幸的是,并不是所有的Gradle插件都能在插件门户上找到(看着你,Android Gradle Plugin! 😡).

我们怎样才能应用这些既不是 "核心 "也没有发布到Plugin Portal的插件呢?

有一个相当不错的技巧可以做到这一点。在我看来,这需要在settings.gradle.kts中编写一些 "模板代码",但这是值得做的。

pluginManagement {
  repositories {
    gradlePluginPortal()
    jcenter()
    google()
  }
  resolutionStrategy {
    eachPlugin {
      if (requested.id.id == "com.android.application") {
        useModule("com.android.tools.build:gradle:${requested.version}")
      }
    }
  }
}

首先,我们必须定义所有 "plugin "块应该寻找插件的存储库(顺序很重要*)。在eachPlugin块中,我们可以查看每个应用的插件(从id("name")),并基于此进行操作。在我们的例子中,我们可以这样说。 "if id equals com.android.application then use "this" as module"。

*这个顺序其实并不 "重要"。但是Gradle会按照给定的顺序在这些仓库中寻找应用的插件。你可能想先添加有最多插件的仓库。

你可能会问useModule中的字符串是什么?它就是我们在传统的buildscript块中使用的classpath字符串。

有了这些信息,Gradle就知道在哪里看,如何在plugins块中搜索插件了。很酷,不是吗?😎

最后我们能够像这样应用Android Gradle插件

plugins {
    id("com.android.application") version "3.1.1"
}

是时候改变了,现在!

版本问题

Gradle是为模块化设计的。这意味着一个项目可以包含不同的模块,这些模块可以应用不同(或相同)的插件。如果你这样做,你可能会有这样的结局。

// project/app/build.gradle.kts
plugins {
  id("com.android.application") version "3.1.1"
  kotlin("android") version "1.2.40"
}
// project/library1/build.gradle.kts
plugins {
  id("com.android.library") version "3.1.1"
  kotlin("android") version "1.2.40"
}
// project/library2/build.gradle.kts
plugins {
  id("com.android.library") version "3.1.1"
  kotlin("android") version "1.2.40"
  kotlin("kapt") version "1.2.40"
}

想象一下,你想更新应用的插件。在每个build.gradle.kts文件中跳转并更改版本,真的很烦人(除了可能导致错误之外。例如,你忘记了一个Gradle文件或使用了错误的版本)。但是有帮助。另一个时候,Gradle设置可以帮助我们。

有趣的事实:作为一个Android开发者,你可能从未接触过settings.gradle,甚至不知道它的存在,对吗? 😉

除了只添加useModule(用于插件门户中缺少的插件),我们还可以额外使用useVersion。对于所有的插件! 即使它们已经发布到插件门户(对于所有的Kotlin插件来说都是如此)。

pluginManagement { 
  repositories { ... }
  eachPlugin { 
    if (requested.id.id.startsWith("com.android")) {
      useModule("com.android.tools.build:gradle:3.1.1")
    }
    if (requested.id.id.startsWith("org.jetbrains.kotlin")) {
      useVersion("1.2.31")
    }
  } 
}

有了这个小小的改变,我们就可以在没有定义版本的情况下应用我们的插件。现在Gradle知道所有以 "com.android "和 "org.jetbrains.kotlin "开头的插件的具体版本。

plugins {
  id("com.android.application") 
  kotlin("android") 
  kotlin("kapt")
}

摘要

  • 删除buildcript块
  • 复制并粘贴上面的代码到你的settings.gradle中。
  • 使用插件块和舞蹈 🕺

www.deepl.com 翻译