使用库构建 Kotlin 应用程序示例
您可以使用 IntelliJ 原生导入器 或 Eclipse Buildship 在 IDE 中打开此示例。 |
为了使您的软件项目能够增长,您可以将 Gradle 项目组织成多个子项目,以模块化您正在构建的软件。在本指南中,您将学习如何在 Kotlin 应用程序的示例中构建这样的项目。但是,这些通用概念适用于您使用 Gradle 构建的任何软件。您可以按照指南逐步创建新的项目,也可以使用上面的链接下载完整的示例项目。
您将构建的内容
您将构建一个 Kotlin 应用程序,它包含一个应用程序和多个库项目。
您需要的内容
-
文本编辑器或 IDE - 例如 IntelliJ IDEA
-
Java 开发工具包 (JDK),版本 8 或更高 - 例如 AdoptOpenJDK
-
最新的 Gradle 发行版
创建项目文件夹
Gradle 自带一个名为 init
的内置任务,用于在空文件夹中初始化一个新的 Gradle 项目。init
任务使用(也是内置的)wrapper
任务来创建 Gradle 包装器脚本 gradlew
。
第一步是为新项目创建一个文件夹,并进入该文件夹。
$ mkdir demo $ cd demo
运行 init 任务
在新项目目录中,使用终端中的以下命令运行 init
任务:gradle init
。当出现提示时,选择 1: application
项目类型和 2: Kotlin
作为实现语言。之后,选择 2: Add library projects
。接下来,您可以选择用于编写构建脚本的 DSL - 1 : Groovy
或 2: Kotlin
。对于其他问题,按回车键使用默认值。
输出将如下所示
$ gradle init Select type of project to generate: 1: basic 2: application 3: library 4: Gradle plugin Enter selection (default: basic) [1..4] 1 Split functionality across multiple subprojects?: 1: no - only one application project 2: yes - application and library projects Enter selection (default: no - only one application project) [1..2] 2 Select implementation language: 1: C++ 2: Groovy 3: Java 4: Kotlin 5: Scala 6: Swift Enter selection (default: Java) [1..6] 2 Select build script DSL: 1: Groovy 2: Kotlin Enter selection (default: Groovy) [1..2] 1 Project name (default: demo): Source package (default: demo): BUILD SUCCESSFUL 2 actionable tasks: 2 executed
init
任务会生成具有以下结构的新项目
├── gradle (1)
│ ├── libs.versions.toml (2)
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle.kts (4)
├── buildSrc
│ ├── build.gradle.kts (5)
│ ├── settings.gradle.kts (5)
│ └── src
│ └── main
│ └── kotlin (6)
│ ├── buildlogic.kotlin-application-conventions.gradle.kts
│ ├── buildlogic.kotlin-common-conventions.gradle.kts
│ └── buildlogic.kotlin-library-conventions.gradle.kts
├── app
│ ├── build.gradle.kts (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── app
│ │ ├── App.java
│ │ └── MessageUtils.kt
│ └── test (9)
│ └── java
│ └── demo
│ └── app
│ └── MessageUtilsTest.kt
├── list
│ ├── build.gradle.kts (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── list
│ │ └── LinkedList.kt
│ └── test (9)
│ └── java
│ └── demo
│ └── list
│ └── LinkedListTest.kt
└── utilities
├── build.gradle.kts (7)
└── src
└── main (8)
└── java
└── demo
└── utilities
├── JoinUtils.kt
├── SplitUtils.kt
└── StringUtils.kt
├── gradle (1)
│ ├── libs.versions.toml (2)
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle (4)
├── buildSrc
│ ├── build.gradle (5)
│ ├── settings.gradle (5)
│ └── src
│ └── main
│ └── groovy (6)
│ ├── buildlogic.kotlin-application-conventions.gradle
│ ├── buildlogic.kotlin-common-conventions.gradle
│ └── buildlogic.kotlin-library-conventions.gradle
├── app
│ ├── build.gradle (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── app
│ │ ├── App.java
│ │ └── MessageUtils.java
│ └── test (9)
│ └── java
│ └── demo
│ └── app
│ └── MessageUtilsTest.java
├── list
│ ├── build.gradle (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── list
│ │ └── LinkedList.java
│ └── test (9)
│ └── java
│ └── demo
│ └── list
│ └── LinkedListTest.java
└── utilities
├── build.gradle (7)
└── src
└── main (8)
└── java
└── demo
└── utilities
├── JoinUtils.java
├── SplitUtils.java
└── StringUtils.java
1 | 为包装器文件生成的文件夹 |
2 | 生成的版本目录 |
3 | Gradle 包装器启动脚本 |
4 | 设置文件,用于定义构建名称和子项目 |
5 | buildSrc 的构建脚本,用于配置构建逻辑的依赖项 |
6 | 约定插件的源文件夹,用 Groovy 或 Kotlin DSL 编写 |
7 | 三个子项目的构建脚本 - app 、list 和 utilities |
8 | 每个子项目中的 Kotlin 源文件夹 |
9 | 子项目中的 Kotlin 测试源文件夹 |
现在您已经设置了项目,可以构建一个模块化为多个子项目的 Kotlin 应用程序。
查看项目文件
settings.gradle(.kts)
文件有两行有趣的代码
rootProject.name = "demo"
include("app", "list", "utilities")
rootProject.name = 'demo'
include('app', 'list', 'utilities')
-
rootProject.name
为构建分配一个名称,这将覆盖根据其所在目录命名构建的默认行为。建议设置一个固定名称,因为如果项目是共享的(例如作为 Git 存储库的根目录),文件夹可能会更改。 -
include("app", "list", "utilities")
定义构建包含对应文件夹中的三个子项目。可以通过扩展列表或添加更多include(…)
语句来添加更多子项目。
由于我们的构建包含多个子项目,因此我们希望在它们之间共享构建逻辑和配置。为此,我们利用所谓的约定插件,这些插件位于 buildSrc
文件夹中。buildSrc
中的约定插件是一种简单的方法,可以利用 Gradle 的插件系统来编写可重用的构建配置片段。
在这个示例中,我们可以找到三个这样的约定插件,它们是基于彼此的
plugins {
id("org.jetbrains.kotlin.jvm") (1)
}
repositories {
mavenCentral() (2)
}
dependencies {
constraints {
implementation("org.apache.commons:commons-text:1.11.0") (3)
}
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") (4)
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
tasks.named<Test>("test") {
useJUnitPlatform() (5)
}
plugins {
id 'org.jetbrains.kotlin.jvm' (1)
}
repositories {
mavenCentral() (2)
}
dependencies {
constraints {
implementation 'org.apache.commons:commons-text:1.11.0' (3)
}
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1' (4)
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform() (5)
}
kotlin-common-conventions
定义了一些所有 Kotlin 项目应该共享的配置,无论它们是库还是实际的应用程序。首先,我们应用 Kotlin Gradle 插件 (1) 以使所有用于构建 Kotlin 项目的功能都可用。然后,我们声明一个仓库 - mavenCentral()
- 作为外部依赖项的来源 (2),定义依赖项约束 (3) 以及所有子项目共享的标准依赖项,并将 JUnit 5 设置为测试框架 (4…)。其他共享设置,例如编译器标志或 JVM 版本兼容性,也可以在这里设置。
plugins {
id("buildlogic.kotlin-common-conventions") (1)
`java-library` (2)
}
plugins {
id 'buildlogic.kotlin-common-conventions' (1)
id 'java-library' (2)
}
plugins {
id("buildlogic.kotlin-common-conventions") (1)
application (2)
}
plugins {
id 'buildlogic.kotlin-common-conventions' (1)
id 'application' (2)
}
kotlin-library-conventions
和 kotlin-application-conventions
都应用了 kotlin-common-conventions
插件 (1),以便在那里执行的配置由库和应用程序项目共享。接下来,它们分别应用 java-library
或 application
插件 (2),从而将我们的通用配置逻辑与库或应用程序的具体内容相结合。虽然在这个示例中没有更细粒度的配置,但库或应用程序项目特定的构建配置可以进入这些约定插件脚本中的一个。
让我们看一下子项目中的 build.gradle(.kts)
文件。
plugins {
id("buildlogic.kotlin-application-conventions")
}
dependencies {
implementation("org.apache.commons:commons-text")
implementation(project(":utilities"))
}
application {
mainClass = "demo.app.AppKt" (1)
}
plugins {
id 'buildlogic.kotlin-application-conventions'
}
dependencies {
implementation 'org.apache.commons:commons-text'
implementation project(':utilities')
}
application {
mainClass = 'demo.app.AppKt' (1)
}
plugins {
id("buildlogic.kotlin-library-conventions")
}
plugins {
id 'buildlogic.kotlin-library-conventions'
}
plugins {
id("buildlogic.kotlin-library-conventions")
}
dependencies {
api(project(":list"))
}
plugins {
id 'buildlogic.kotlin-library-conventions'
}
dependencies {
api project(':list')
}
查看构建脚本,我们可以看到它们包含最多三个块
-
每个构建脚本都应该有一个
plugins {}
块来应用插件。在一个结构良好的构建中,它可能只应用一个约定插件,如本例所示。约定插件将负责应用和配置核心 Gradle 插件(如application
或java-library
)其他约定插件或来自插件门户的社区插件。 -
其次,如果项目有依赖项,则应添加一个
dependencies {}
块。依赖项可以是外部的,例如我们在kotlin-common-conventions
中添加的JUnit依赖项,也可以指向其他本地子项目。为此,使用project(…)
符号。在我们的示例中,utilities
库需要list
库。而app
则使用utilities
库。如果本地项目相互依赖,Gradle 会在需要时(且仅在需要时)构建依赖项目。要了解更多信息,请查看有关Gradle 中的依赖项管理的文档。 -
第三,可能存在一个或多个用于插件的配置块。这些配置块仅应在直接构建脚本中使用,前提是它们为单个项目配置了特定内容。否则,此类配置也属于约定插件。在本例中,我们使用
application {}
块(特定于application
插件),在我们的app
项目中将mainClass
设置为demo.app.App
**(1)**。
我们拥有的最后一个构建文件是buildSrc
中的build.gradle(.kts)
文件。
plugins {
`kotlin-dsl` (1)
}
repositories {
gradlePluginPortal() (2)
}
dependencies {
implementation(libs.kotlin.gradle.plugin)
}
plugins {
id 'groovy-gradle-plugin' (1)
}
repositories {
gradlePluginPortal() (2)
}
dependencies {
implementation libs.kotlin.gradle.plugin
}
此文件为构建约定插件本身奠定了基础。通过应用用于插件开发的插件之一——groovy-gradle-plugin
或kotlin-dsl
——**(1)**,我们启用了将约定插件作为buildSrc
中的构建文件编写的支持。这些正是我们上面已经检查过的约定插件。此外,我们添加了 Gradle 的插件门户作为存储库 **(2)**,这使我们能够访问社区插件。要使用插件,需要在dependencies {}
块中将其声明为依赖项。
除了 Gradle 构建文件之外,您还可以在相应的文件夹中找到示例 Kotlin 源代码和测试源代码。随意修改这些生成的源代码和测试,以探索 Gradle 在运行构建时如何对更改做出反应,如下一节所述。
运行测试
您可以使用./gradlew check
执行所有子项目中的所有测试。当您使用简单的任务名称(如check
)调用 Gradle 时,该任务将在提供该任务的所有子项目中执行。要仅针对特定子项目,可以使用任务的完整路径。例如,:app:check
将仅执行app
项目的测试。但是,在本例中,其他子项目仍将被编译,因为app
声明了对它们的依赖关系。
$ ./gradlew check BUILD SUCCESSFUL 9 actionable tasks: 9 executed
如果所有测试都成功通过,Gradle 不会在控制台中打印更多输出。您可以在<subproject>/build/reports
文件夹中找到测试报告。随意更改一些示例代码或测试并重新运行check
以查看测试失败时会发生什么。
运行应用程序
由于application
插件,您可以直接从命令行运行应用程序。run
任务告诉 Gradle 执行分配给mainClass
属性的类中的main
方法。
$ ./gradlew run > Task :app:run Hello world! BUILD SUCCESSFUL 2 actionable tasks: 2 executed
您第一次运行包装器脚本gradlew 时,可能会延迟一段时间,因为该版本的gradle 将被下载并存储在您的~/.gradle/wrapper/dists 文件夹中。
|
捆绑应用程序
application
插件还会将应用程序及其所有依赖项捆绑在一起。该存档还将包含一个脚本,用于使用单个命令启动应用程序。
$ ./gradlew build BUILD SUCCESSFUL in 0s 8 actionable tasks: 8 executed
如果您运行如上所示的完整构建,Gradle 将为您生成两种格式的存档:app/build/distributions/app.tar
和app/build/distributions/app.zip
。
发布构建扫描
了解构建在幕后执行情况的最佳方法是发布构建扫描。为此,只需使用--scan
标志运行 Gradle 即可。
$ ./gradlew build --scan BUILD SUCCESSFUL in 0s 8 actionable tasks: 8 executed Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service. Do you accept these terms? [yes, no] yes Gradle Terms of Service accepted. Publishing build scan... https://gradle.com/s/5u4w3gxeurtd2
单击链接并探索执行了哪些任务、下载了哪些依赖项以及更多详细信息!
总结
就是这样!您现在已经成功使用 Gradle 配置和构建了 Kotlin 应用程序项目。您已经了解了如何
-
初始化一个生成 Kotlin 应用程序的项目
-
通过组合多个子项目来创建模块化软件项目
-
使用
buildSrc
中的约定插件在子项目之间共享构建配置逻辑 -
在所有子项目中运行类似名称的任务
-
在特定子项目中运行任务
-
构建、捆绑和运行应用程序
下一步
当您的项目发展壮大时,您可能对有关如何配置 JVM 项目、构建多项目构建和依赖项管理的更多详细信息感兴趣