百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Gradle:从新手到基础扎实(gradle教程)

toyiye 2024-08-09 10:25 30 浏览 0 评论


在 Kotlin 上进行开发时,每个初学者都面临着不了解使用该编程语言的适当工具的问题。这就是本文的目的 - 解释 Gradle for Kotlin 以及 Kotlin 上的工作。我们走吧!

?定义
Gradle是一个使用一组工具自动组装(构建、编译)程序的系统。

但让我们从简单的事情开始 - 如何使用 Gradle 创建我们的第一个项目?

项目

让我们从应用程序构建系统中存在的基本概念——项目开始。

?定义
项目是应用程序组织的一个独立单元,作为一组依赖模块和规则。

模块是一个独立的代码组织单元,具有一定的规则(如何构建等)。其存在的目的与 Kotlin 中的包相同——将代码划分为逻辑块,以提高源代码的质量(在一个项目和其他项目中重用代码)。

我在说什么规则?事实上,一切都非常简单 - 我们描述我们的项目将如何构建(技术特性的描述)、针对哪个平台(例如 Android 或 iOS)、使用哪种语言以及使用哪种方式(项目依赖项)。

结构

让我们创建一个示例项目结构:


PS:示例中的名称没有特殊意义,它们只是Foobar的术语。

所有模块都需要具备build.gradle.kts才能工作。重要的是要注意,模块不能单独存在,只有当我们通过以下方式将它们显式包含到我们的项目中时,它们才起作用settings.gradle.kts

正如你所看到的,我们有一种“首席主管”,他决定哪些模块将出现在我们的项目中以及它们将如何工作,以及“本地主管”,他们只为他们下属的代码(模块)设置规则,但是,值得注意的是,在规则方面,项目比模块具有更高的优先级(但这不是我们将在这篇特定文章中介绍的内容)。

有什么规则?事实上,它们有很多 - 这完全取决于你做什么,但基本的是,例如:

  • 项目名称、版本、组(类似于 Kotlin 的包的标识符)
  • 编程语言(Java / Scala / Groovy / Kotlin / 等)
  • 平台(仅与 Kotlin 相关,更清楚地说,与 Kotlin 多平台插件相关)
  • 依赖关系(代码中使用的库或框架)

模块

让我们考虑一下这些模块:它们的食用方式和食用内容。让我提醒您什么是模块:

?定义
模块是代码组织的独立单元,具有一组定义模块行为的正式规则。

以模块为例foo: 要创建一个模块,首先我们创建该模块的目录。之后,我们创建一个名为 的文件(或者如果您使用 Groovy 作为脚本语言,没有其他方法),我们已经在其中规定了我们的模块可以执行的操作。



要创建模块,首先,我们创建该模块的目录。 之后,我们创建一个名为 build.gradle.kts 的文件(如果您使用 Groovy 作为脚本语言,则为 build.gradle),我们已经在其中规定了我们的模块可以执行的操作。

build.gradle.kts

我们的设置文件具有以下结构:


别害怕! 即使看起来相当复杂。

任何 build.gradle.kts 中的主要组件都是 Plugins 块。 依赖项和存储库块独立于插件块,但如果没有它,它们就像在空荡荡的剧院里讲笑话的喜剧演员一样 - 他们可能有一些很棒的材料,但没有舞台,没有观众,也听不到笑声。

应用于模块的插件通常会使用您在“依赖项”块中指定的内容。 因此,没有使用它的插件的依赖项是没有用的,这就是为什么依赖项与我们方案中的插件有联系。

存储库本身并不依赖于插件,但您始终需要它们将任何依赖项或插件应用到您的项目。 因此,如果没有插件或依赖项,它的存在就没有意义。 因此,用我们之前的类比来说,这就像一个挤满了人的剧院,但舞台上没有喜剧演员。

任务也是 Gradle 配置文件中的基本内容。 它们始终由您应用于模块的插件提供。 在没有任何插件的空模块中,您不会有任何任务。 但是,在项目级别上可以执行一些基本任务:

任务(返回整个项目中可用任务的列表:名称、任务所依赖的任务等)。

依赖项(打印项目依赖项的报告,显示使用了哪些依赖项及其版本)

帮助(返回整个项目中可用任务的列表以及简要说明)。

模型(提供项目结构、任务等的详细报告;帮助您理解和调试 Gradle 构建)

BonusTasks 可以依赖于其他任务,当您需要其他任务执行的结果时,它特别有用。

例子

现在,让我们考虑一个例子。 例如,让我们创建一个 Kotlin/JVM 项目,并使用 kotlinx.coroutines 库作为依赖项。

首先,我们需要在项目的根目录中创建项目配置文件 – settings.gradle.kts:

rootProject.name = "our-first-project"

为了使其正常工作,您应该在 IDE 中运行 gradlesync:


您可以为新模块创建一个新文件夹,也可以以相同的方式将根文件夹用作模块,只需在根目录中添加 build.gradle.kts 文件 (our-first-project/build.gradle.kts) 。

?? 重要当我们使用根文件夹作为模块时,我们不需要显式地将其添加到项目配置文件中,但是对于任何新模块,我们应该使用 include 函数来声明它 - 例如, include(":foo") ( 对于嵌套文件夹,请使用 include(":foo:bar"))

让我们从插件开始:

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.9.0"
}

Bonus我们可以使用 kotlin 函数来简化 Kotlin 插件(例如 jvm、android、js、multiplatform)的声明: id("org.jetbrains.kotlin.jvm") -> kotlin("jvm")。它会自动附加 org. jetbrains.kotlin 开头。

现在,让我们来看看依赖关系:

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}

我们的 Kotlin/JVM 插件提供了一个对我们有用的功能——实现。 如果没有它,我们将不得不显式地编写一个配置名称(插件的标识符)来消耗我们的依赖项。 您还记得,依赖项并不是独立存在的。 因此,更清楚地说,依赖项块仅提供添加和使用添加的依赖项的基本功能。 我们可以通过以下方式添加依赖项(但我们仍然需要一个插件来使用它):

dependencies {
    add(configurationName = "implementation", "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}

ConfigurationName 代表将依赖项与不同的目标插件(正在消耗我们的依赖项的插件)分开。

但是,如果我们尝试构建我们的模块,我们将遇到下一个问题:

Could not resolve all dependencies for configuration ':compileClasspath'. > Could not find org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3.

要解决此问题,我们需要指定要从中实现依赖项的存储库。 让我们看一下例子:

repositories {
    // builtins:
    mavenCentral()
    mavenLocal()
    google()

    // or specify exact link to repository:
    maven("https://maven.y9vad9.com")
}

? DefinitionMaven 存储库 – 就像在线商店或代码库。 它们是预构建的软件库和依赖项的集合,您可以在项目中轻松访问和使用它们。 这些存储库提供了一种集中且有组织的方式来共享和分发代码。

另外,值得注意的是,Maven 是另一个具有 Gradle 内置支持的构建工具。

但是,对于我们的例子,我们只需要在 mavenCentral() 中。 因此,我们生成的 build.gradle.kts 如下:

plugins {
    kotlin("jvm") version "1.9.0"
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}

对于这样的例子,我们不需要接触任何任务。 但值得一提的是,我们的 Kotlin 插件提供了以下任务:

编译Kotlin

编译Java

ETC

但是,通常,您不需要直接调用这些任务,除非您正在开发自己的依赖于这些任务的结果/输出的插件。

Bonus您可以使用命令行或通过 IDE 运行 gradle 任务:


作为一个例子,我以 gradle 构建任务为例。

我们现在将跳过任务及其使用方法的完整说明。 我将在接下来的文章中介绍它。

现在,我们终于来看看如何以及在哪里编写代码。

源集

我们弄清楚了如何创建项目和模块,但是我们应该在哪里编写代码呢? 在Gradle项目中,有一个不同源代码集(Source Sets)的概念——一种针对不同需求的代码分离。 例如,对于我们前面的示例,默认存在以下集合:

main – 顾名思义,它是放置代码的主要位置。

test – 用于与测试相关的代码。 它依赖于主源集,并具有您在 main.c 中编写的所有依赖项/代码。

Bonus 但情况并非总是如此,例如,Kotlin/多平台项目为您正在编写的每个平台都有专用的源集(基本上,该插件为我们需要的所有平台创建了一组源集)。 因此,值得一提的是,它始终取决于您应用于模块的插件以及您的配置。 这不是一个常数。

主要的

要开始编码,我们需要为我们的编程语言创建一个文件夹,对于 Kotlin,它是 src/main/kotlin 文件夹。 因此,从现在开始,我们可以简单地创建“Hello, World!” 项目。 让我们在最近创建的文件夹中创建 Main.kt:

fun main() = println("Hello, Kotlin!")

您可以使用 IDE 运行它,它会自动处理 Gradle 构建过程。

测试

正如我之前告诉您的,该源集用于测试目的。 但值得一提的是,它有自己的依赖项(但它也从主源集派生)。 因此,您可以实现此源集中可用的依赖项。 例如,让我们实现 kotlin.test 库:

dependencies {
    // ...
    testImplementation(kotlin("test"))
}

您可以参阅 Kotlin 文档中的完整教程,了解如何使用 kotlin.test 测试代码。

多模块项目

不同模块的创建需要它们之间的交互。 另外,让我们分析一下交互的类型,你不能或不应该做什么,以及有什么意义。 开始吧!

如果您还记得我们最初的项目结构,它有几个模块:

  • foo
  • bar
  • qux

让我们将 foo 视为主模块,我们在其中拥有应用程序的入口点(Main.kt 文件)。 让我们开始为所有三个模块创建配置(这很简单,没有任何依赖项):

plugins {
    kotlin("jvm") version ("1.9.0")
}

repositories {
    mavenCentral()
}

为了使它工作,让我们将我们的模块添加到settings.gradle.kts:

rootProject.name = "example"

include(":foo", ":bar", "qux")

然后,让 foo 依赖于 bar 模块:

// File: /foo/build.gradle.kts

dependencies {
    implementation(project(":bar"))
}

?? 重要要从项目中实现模块,您应该使用项目函数指定它。 当实现模块或在其他地方指定它时,我们使用特殊的符号,其中 / 被替换为 : 符号。

还有额外的好处:要实现根模块,只需使用implementation(project(":"))。

从现在开始,我们可以使用 foo 模块内 bar 中的任何函数或类(当然,如果这些声明的可见性允许的话)。 例如,让我们在 foo 模块中创建一个文件:

package com.my.project

fun printMeow() = println("Meow!")

我们可以在 foo 模块中使用它:

import com.my.project.printMeow

fun main() = printMeow()

但是,无法从 qux 模块使用它。 此外,如果我们尝试实现 foo 模块,bar 仍然无法访问。 默认情况下,模块的依赖关系不会暴露给其他模块。

Bonus我们可以使用 api 函数而不是实现来共享实现我们特定模块的模块的依赖关系。 这样,例如 qux 模块可以通过实现 foo 来访问 bar 模块函数/类/等,而无需显式依赖 bar 模块。

局限性

想象一下,在前面的示例之后,您需要获取任何类/函数/等。 foo 模块中的 bar 内部。 如果您尝试这样做,您将遇到下一个问题:

Circular dependency between the following tasks:
:bar:classes
\--- :bar:compileJava
     +--- :bar:compileKotlin
     |    \--- :foo:jar
     |         +--- :foo:classes
     |         |    \--- :foo:compileJava
     |         |         +--- :bar:jar
     |         |         |    +--- :bar:classes (*)
     |         |         |    +--- :bar:compileJava (*)
     |         |         |    \--- :bar:compileKotlin (*)
     |         |         \--- :foo:compileKotlin
     |         |              \--- :bar:jar (*)
     |         +--- :foo:compileJava (*)
     |         \--- :foo:compileKotlin (*)
     \--- :foo:jar (*)

这是什么一回事呢? 一切都很简单——你不能创建循环依赖。

Gradle 中的循环依赖就像一个永无休止的循环,它会使您的构建过程陷入困境,因为任务一直在等待彼此完成,而这种情况永远不会发生。 避免它们对于确保您的构建顺利运行至关重要。 此外,违反依赖倒置原则总是不好的做法。

您可以参考此讨论以了解更多信息。

? 有经验的人的奖励通常,如果我们谈论移动应用程序,我们会使用三层架构。 因此,最好将其划分为不同的模块以强制执行架构规则:


例如,它使得我们的领域层不依赖于数据层——这实际上是不可能的,因为会存在循环依赖问题。

结论

这不仅仅是另一种咖啡冲泡方法;它是一种咖啡冲泡方法。 它是一个强大的构建自动化工具,可以简化您的软件开发过程。 使用 Gradle,您可以管理依赖项、自动执行任务并保持项目井井有条。 这就像有一个值得信赖的助手来处理细节,这样您就可以专注于编写出色的代码!

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码