我们中的许多人都遇到过Groovy的困难,并习惯于将其转换为Kotlin DSL。 然后,作为Android工程师,在完全使用Kotlin编写的项目上工作是纯粹的喜悦。
我们假设采用基于功能的模块化应用程序结构,并应用版本目录(version catalog
)功能。我们将充分管理构建逻辑,使其集中化并可由模块重用。
以下是通过创建您的自定义插件脚本来促进Gradle构建配置成为集中化构建逻辑的步骤。
我们所有人都通常采用的方法是将自定义脚本放置到默认的buildSrc模块中。先前不推荐使用buildSrc实现,因为它会使构建缓存失效,并在每次更改依赖项时同步整个项目。它现在被视为Gradle 8中的一个包含式构建。
在项目设置脚本中,我们将配置脚本移动到一个构建逻辑复合构建模块中。
第一个 pluginManagement 块确保 Gradle 使用适当的插件存储库。我们将我们的新模块包含在构建中,并明确指定我们需要的存储库。
另一个关键元素是集中式依赖声明中的解析模式,你可以声明以强制 Gradle 始终获取正确的依赖项。在此示例中,我们将使用项目设置中声明的存储库。
settings.gradle.kts
@file:Suppress("UnstableApiUsage")
enableFeaturePreview("VERSION_CATALOGS")
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
pluginManagement {
includeBuild("build-logic")
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "GradleKotlinConventionPlugins"
include(":app")
在设置脚本中启用版本目录功能后,我们开始使用新的复合模块。
settings.gradle.kts
@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"
现在,我们将我们的新模块定义为Kotlin脚本,通过启用Kotlin DSL并强制使用预编译的脚本插件将其作为 Kotlin 源集的一部分。
因此,作为项目构建的组成部分的复合模块负责配置,这通常是我们在项目级 Gradle 构建脚本中处理的。 我们将 Gradle 特定的声明移动到那里。
build.gradle.kts
plugins {
`kotlin-dsl`
`kotlin-dsl-precompiled-script-plugins`
}
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
dependencies {
implementation(libs.kotlin.gradlePlugin)
implementation(libs.gradle)
}
tasks.test {
useJUnitPlatform()
}
在基于特征的模块化应用结构中,我们有主应用模块、功能模块和共享模块(用于一些可重用的逻辑或数据)等。
我们确定的主要规范插件包括:
Kotlin 库惯例通常用于声明一些 API 或共享一些逻辑。它是一个覆盖了 JDK 版本的 Java 库。
kotlin-library-conventions.gradle.kts
plugins {
`java-library`
kotlin("jvm")
}
kotlin {
jvmToolchain(jdkVersion = 11)
}
task("testUnitTest") {
dependsOn("test")
}
Kotlin Android 库规范适用于默认启用 ViewBinding 功能的特征模块。
kotlin-android-library-conventions.gradle.kts
plugins {
id("com.android.library")
kotlin("android")
}
@Suppress("UnstableApiUsage")
android {
. . .
compileOptions {
isCoreLibraryDesugaringEnabled = true
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
buildFeatures {
viewBinding = true
}
}
dependencies {
. . .
}
它是先前库约定的扩展,具有与 Jetpack Compose 相关的声明。
kotlin-android-composable-library-conventions.gradle.kts
plugins {
id("kotlin-android-library-conventions")
}
@Suppress("UnstableApiUsage")
android {
buildFeatures.compose = true
composeOptions.kotlinCompilerExtensionVersion = libs.versionKotlinCompiler
}
dependencies {
implementation(platform(libs.libAndroidxComposeBom))
implementation(libs.libAndroidxComposeFoundation)
}
创建新模块时,通过应用传统插件和额外的依赖项来定义构建脚本会更加容易。我们也可以考虑将组合模块应用于另一个项目。
当我们创建一个新模块时,可以通过应用公约插件和附加的依赖项,更容易地定义构建脚本。我们还可以考虑将组合模块应用于另一个项目。
feature-build.gradle.kts
plugins {
id("kotlin-android-library-conventions")
id("test-conventions")
}
dependencies {
implementation(libs.androidX.appCompat)
implementation(libs.google.material)
}
总之,模块化是我们解决诸多问题的主要关注点,如代码库大小、可扩展性、可读性、代码质量、代码重复等。我们通常会按照特性来划分模块,将特性代码进行隔离。Google Android团队最近也发布了一份应用程序模块化指南,采用了相同的方法。
https://developer.android.com/topic/modularization
但也有一些与版本目录相关的限制性问题。库不是直接可访问的,我们需要创建一些扩展函数来解决这个问题。插件在插件块中也不被识别。这个问题似乎在Gradle 8中已经得到解决。
您可以在我的Github规范repository中找到所有的源代码。
https://github.com/uteke/gradle-kotlin-convention-plugins