Kotlin scripting 的优势

关于开发者来说,保证整个项目中言语和代码的一致性是很重要的。尤其是关于 Android 开发者来说,运用 Kotlin 言语编写事务代码,同样也希望运用 Kotlin 言语来构建项目。尽管 Kotlin 脚本 现在还是 Experimental 的,可是 Gradle Kotlin DSL 现已满足成熟和稳定,能够胜任 Android 的构建办理
除此之外,Kotlin 脚本相关于 Groovy 来说可读性更高,也更利于 IDE 的语法查看、主动补全和跳转。所以迁移至 Kotlin 脚本是一个很好的挑选

基础运用

尖端 settings.gradle.kts

尖端 settings.gradle.kts 用来界说工程级的库房装备以及用来构建应用的 module

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "My Application"
include(":app")

pluginManagement() 用来装备各种 Gradle 插件的装备,包含插件所属库房、依靠处理策略、依靠版别等
dependencyResolutionManagement() 用来装备 Project 以及各个子 module 共用的库房和依靠(module 独有的依靠最好在 module 自己的 build.gradle.kts 中装备)

尖端 build.gradle.kts

尖端 build.gradle.kts 用来界说 Project 以及各个子 module 共用的插件和特点

plugins {
    id("com.android.application") version "8.2.0-alpha02" apply false
    id("org.jetbrains.kotlin.android") version "1.8.10" apply false
}

尽管能够运用如下的办法界说 module 共用的特点,可是为了解耦,尽量不要这样用

ext {
    extra["sdkVersion"] = 33
    extra["appcompatVersion"] = "1.6.1"
}
// compileSdk = rootProject.extra["sdkVersion"]

module 级 build.gradle.kts

module 级 build.gradle.kts 用来装备 module 自己的依靠和装备信息

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}
android {
    namespace = "com.yourapp.myapplication"
    compileSdk = 33
    defaultConfig {
        applicationId = "com.yourapp.myapplication"
        minSdk = 24
        targetSdk = 33
        versionCode = 1
        versionName = "1.0"
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }
    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.4.3"
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}
dependencies {
    implementation("androidx.core:core-ktx:1.9.0")
}

Groovy 迁移

弥补赋值的 =,如 compileSdkVersion 30 变为 compileSdk = 33
调整字符串语法,如 "$project.rootDir/tools/proguard-rules-debug.pro" 变为 "${project.rootDir}/tools/proguard-rules-debug.pro"
val/var 替换 def 进行变量声明,如 def building64Bit = false 变为 val building64Bit = false
调整 list 和 map 语法,如 jvmOptions += ["-Xms4000m", "-Xmx4000m"] 变为 jvmOptions += listOf("-Xms4000m", "-Xmx4000m")

最佳实践

上面咱们现已提到,在尖端 build.gradle.kts 中界说 module/subproject 共用的特点不利于解耦,那各个 module 怎么高雅地增加中心化的 dependency 和 version 呢?
一种比较好的方式是运用 Gradle version catalog,运用方式就像直接运用目录层级引用相同,如:

implementation(libs.accompanist.systemuicontroller)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core.ktx)

前提是需要在根目录下的 gradle 目录下创立一个 libs.versions.toml 文件,它运用 TOML(一种简练高效的装备文件格式)格式来书写,在这里咱们能够用来声明 [versions], [libraries], [bundles], [plugins],如:

[versions]
accompanist = "0.28.0"
androidGradlePlugin = "8.0.0"
androidxActivity = "1.7.0"
[libraries]
accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanist" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidxActivity" }
[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }

依靠能够用多种方式来声明,"com.mycompany:mylib:1.4", { module = "com.mycompany:other", version = "1.4" } 或许 { group = "com.mycompany", name = "alternate", version = "1.4" } 都能够
假如你不想用默认的 libs 目录名,能够这样来自界说名字:

dependencyResolutionManagement {
    defaultLibrariesExtensionName.set("projectLibs")
}

version catalog 是类型安全的,编译器会主动查看和主动补全。假如在某些场景下不可用,能够测验运用不安全的 API:

val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
dependencies {
    versionCatalog.findLibrary("accompanist-systemuicontroller").ifPresent {
        implementation(it)
    }
}

假如想要在多个团队或许多个项目中共享一个 version catalog 文件,能够这样依靠本地文件:

dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

或许更灵敏一点,把 version catalog 以插件的方式运用:

plugins {
    `version-catalog`
    `maven-publish`
}
catalog {
    versionCatalog {
        library("my-lib", "com.mycompany:mylib:1.2")
    }
}
publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["versionCatalog"])
        }
    }
}
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from("com.mycompany:catalog:1.0")
            version("accompanist", "0.28.0")
        }
    }
}

总之,咱们最终期望的,都是一个类型安全的、中心化的、灵敏解耦的依靠和版别办理,运用 Kotlin + version catalog 现在来说是一个比较好的方案

参阅

  • Configure your build
  • Gradle Kotlin DSL Primer
  • Sharing dependency versions between projects