Kotlin DSL Gradle 指南

Gradle 是用于 Android 应用程序开发的构建工具,可以帮助开发者管理项目的编译,打包,签名等任务,同时支持模块化开发,定制构建流程和多种签名配置,简化了项目管理和提高了开发效率。现在 Android 官方已经默认推荐使用 Kolin DSL 来构建 Gradle 了,那就一起来瞧瞧吧!
初始配置

新建一个项目,看看初始配置。

在这里插入图片描述

我们从上到下来看一看,相关配置的说明都在注释里。

Module 下的 build.gradle.kts

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

android {
    //应用程序的命名空间,主要用于访问应用程序资源。
    namespace = "com.xzj.myapp"
    //编译所依赖的 Android SDK 版本。
    compileSdk = 33

    defaultConfig {
        //APP 的唯一标识
        applicationId = "com.xzj.myapp"
        //支持的最低 API Level,如指定23,表示低于 Android 6.0 的机型不能使用这个 APP。
        minSdk = 23
        //基于哪个 Android 版本开发的,如指定33,代表适配到 Android 13。
        targetSdk = 33
        //版本号
        versionCode = 1
        //版本名称
        versionName = "1.0"

        //指定运行测试时要使用的 InstrumentationRunner,AndroidJUnitRunner 是 Android 测试框架中的一个组件,用于执行针对 Android 应用程序的测试。
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        //表示在项目中使用支持库来处理矢量图像
        vectorDrawables {
            useSupportLibrary = true
        }
    }

    //构建类型,主要用于打包。
    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    //指定 Java 环境版本
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    //指定 JVM 环境
    kotlinOptions {
        jvmTarget = "1.8"
    }
    //是否启用 compose
    buildFeatures {
        compose = true
    }
    //指定了 Compose 所使用的 Kotlin 编译器扩展的版本
    composeOptions {
        kotlinCompilerExtensionVersion = "1.4.3"
    }
    //表示在打包过程中排除项目中位于 "/META-INF/AL2.0" 和 "/META-INF/LGPL2.1" 路径下的资源文件
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}
//依赖
dependencies {

    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
    implementation("androidx.activity:activity-compose:1.7.0")
    implementation(platform("androidx.compose:compose-bom:2023.03.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-tooling")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
}

gradle-wrapper.properties

#Thu Mar 21 18:07:31 CST 2024
#Gradle 压缩包解压后的主目录
distributionBase=GRADLE_USER_HOME
#Gradle 压缩包解压后的具体路径
distributionPath=wrapper/dists
#Gradle 的下载地址
distributionUrl=https://services.gradle.org/distributions/gradle-8.0-bin.zip
#存放 Gradle zip 压缩包的具体路径
zipStoreBase=GRADLE_USER_HOME
#存放 Gradle zip 压缩包的主目录。
zipStorePath=wrapper/dists

Project 下的 build.gradle.kts

//使用 Kotlin DSL 配置 Gradle 插件
plugins {
    id("com.android.application") version "8.1.1" apply false
    id("org.jetbrains.kotlin.android") version "1.8.10" apply false
}

gradle.properties

#设置 JVM 的最大堆内存为 2048MB,指定了文件编码为 UTF-8。
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
#指示项目使用 AndroidX 库
android.useAndroidX=true
#指定 Kotlin 代码风格的规范,official 表示采用官方推荐的代码风格。
kotlin.code.style=official
#用于控制R类是否会传递依赖,当为 true 时,表示类不会被传递到依赖模块中,每个模块会有自己独立的 R 类。
android.nonTransitiveRClass=true

local.properties

## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=/opt/android/sdk

settings.gradle.kts

//插件管理,指定插件下载的仓库。
pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
//依赖管理,指定依赖库下载的仓库,此仓库是有顺序的,顺序决定先从哪个仓库下载。
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
//项目名称
rootProject.name = "MyApp"
//指定参与构建的模块,一个根工程可以有很多的 module,只有在这设置了,gradle 才会去识别,才会在构建的时候被包含进去。
include(":app")
 

生命周期

Task 是 Gradle 构建的核心,生命周期的意义就是在各个阶段把 Task 组合起来,按照我们的意图去构建项目。 Gradle 的生命周期可以分为三个阶段:

  1. 初始化阶段:Gradle 支持单项目和多项目构建,在初始化阶段,Gradle 确定哪些项目将参与构建,并为每个项目创建 Project 实例,比如解析 settings.gradle 文件,以此来决定是单项目构建还是多项目构建。
  2. 配置阶段:解析每个工程的 build.gradle 文件,创建要执行的任务子集和确定各种任务之间的关系,并对任务做一些初始化配置。
  3. 运行阶段:Gradle 根据配置阶段创建和配置的要执行的任务子集,执行任务。

Gradle 也可以监听各个阶段的回调

gradle.addProjectEvaluationListener(object : ProjectEvaluationListener {
    override fun beforeEvaluate(project: Project) {
        println("beforeEvaluate")
    }

    override fun afterEvaluate(project: Project, state: ProjectState) {
        println("afterEvaluate")
    }

})

gradle.addBuildListener(object : BuildListener {

    override fun settingsEvaluated(settings: Settings) {
        println("settingsEvaluated")
    }

    override fun projectsLoaded(gradle: Gradle) {
        println("projectsLoaded")
    }

    override fun projectsEvaluated(gradle: Gradle) {
        println("projectsEvaluated")
    }

    override fun buildFinished(result: BuildResult) {
        println("buildFinished")
    }

})

Gradle 是构建工具本身,而 gradlew 是 Gradle Wrapper 提供的便捷工具,用于在项目中管理和执行 Gradle 构建任务。在 Android 项目中,通常使用 Gradle Wrapper 来统一团队的构建环境,简化项目的配置和维护。

依赖管理

Gradle 提供了强大的依赖管理支持,我们只需声明依赖项即可,Gradle 会帮我们找到所需的 Library,例如依赖项配置和依赖仓库。

dependencies {

    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
    implementation("androidx.activity:activity-compose:1.7.0")
    implementation(platform("androidx.compose:compose-bom:2023.03.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-tooling")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
}

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

需要注意的是,implementation 表示当前引用的第三方库仅限于本 Module 使用,api 表示的依赖是可以传递的。

Gradle 依赖管理进行了优化,如果项目存在同一个依赖库的多个版本,默认选择最高版本,Gradle 会自动排除重复的依赖,这在一定程度上防止了依赖冲突,但是为什么有时还是会遇到依赖冲突的问题呢?举个例子,某些第三方库可能会包含特定版本的某个库,并且你自己的项目中也引入了该库的不同版本,这种情况下,Gradle 会自动选择最高的版本,就可能发生依赖冲突。可以通过如下两种方式解决依赖冲突:

使用 exclude 排除依赖

implementation("com.google.android.exoplayer:exoplayer:2.14.0") {
    exclude(group = "com.google.guava", module = "guava")
}

使用强制版本

configurations.all {
    resolutionStrategy {
        force("com.google.android.exoplayer:exoplayer:2.14.0")
    }
}

Task

Task 是 Gradle 构建的核心对象,我们可以直接在 build.gradle 文件中创建。

创建 Task

tasks.register("xzj") {
    println("create task")
}

也可以这样创建

task("xzj") {
    println("create task")
}

这里需要注意的是:如果有 Task 同名的话,会编译失败。

自定义 Task

继承 DefaultTask,Action 的方法需要添加 @TaskAction 注解。

open class MyTask : DefaultTask() {
    @get:Internal
    var taskName = "taskName"

    @TaskAction
    fun action1() {
        println("action1: $taskName")
    }

    @TaskAction
    fun action2() {
        println("action2: $taskName")
    }

    @TaskAction
    fun action3() {
        println("action3: $taskName")
    }

}

注册自定义的 Task

tasks.register<MyTask>("myTask") {
    taskName = "xzj"
}

然后我们就可以在 AndroidStudio 的 Gradle 工具面板,Tasks -> other 里找到这个 Task,双击执行即可。

在这里插入图片描述

如果是带构造函数传参的话,可以这样

open class MyTask @Inject constructor(private var taskName: String) : DefaultTask() {

    @TaskAction
    fun action1() {
        println("action1: $taskName")
    }

    @TaskAction
    fun action2() {
        println("action2: $taskName")
    }

    @TaskAction
    fun action3() {
        println("action3: $taskName")
    }

}

tasks.register<MyTask>("myTask","argument")

使用 @Inject 注解可以帮助 Gradle 正确地理解带参数的构造函数,并且在创建任务实例时能够正确地调用带参数的构造函数。

doFirst 和 doLast

使用了 doFirst 和 doLast 方法来分别添加在任务执行前和执行后需要执行的动作。

task("hello") {
    doFirst {
        println("doFirst1")
    }
    doFirst {
        println("doFirst2")
    }
    println("hello")
    doLast {
        println("doLast1")
    }
    doLast {
        println("doLast2")
    }
}

执行这个 Task,输出如下:

image.png

doFirst 是倒序执行,doLast 是正序执行,Action 也是正序执行。

当你定义一个任务时,任务的配置代码会在 Gradle 构建脚本解析执行阶段就会执行,而不是在任务实际执行时才执行。因此,当 Gradle 解析执行到 println(“hello”) 这行代码时,会立即执行该代码并先打印出 hello。

dependsOn

dependsOn 用来定义任务之间的依赖关系,通过使用 dependsOn,可以确保一个任务在另一个任务之前执行,从而控制任务的执行顺序。举个例子,有两个任务 A 和 B,想让任务 B 在任务 A 执行完成后再执行,这样干:

tasks.register("taskA") {
    doLast {
        println("Running task A")
    }
}

tasks.register("taskB") {
    dependsOn("taskA")
    doLast {
        println("Running task B")
    }
}

执行 taskB 会先执行 taskA

image.png

finalizedBy

dependsOn 指定的是上一个任务,而 finalizedBy 指定下一个任务,比如想让任务 A 执行后,再去执行任务 B,这样干:

tasks.register("taskA") {
    finalizedBy("taskB")
    doLast {
        println("Running task A")
    }
}

tasks.register("taskB") {
    doLast {
        println("Running task B")
    }
}

onlyIf

onlyIf 是一个条件断言方法,用于指定任务是否应该执行的条件。当条件为 true 时,任务才会执行,否则任务将被跳过。

tasks.register("taskA") {
    val flag = providers.gradleProperty("flag")
    onlyIf { //如果属性存在,则返回 true
        flag.isPresent
    }
    doLast {
        println("Running A")
    }
}

enabled

enable 是 Task 的开关,禁用之后任何操作都不会执行,可以实现和 onlyIf 一样的效果。

tasks.register("taskA") {
    enabled = true
    doLast {
        println("Running A")
    }
}

查找 Task

tasks.findByName("taskA")?.doFirst {
    println("taskA findByName")
}

tasks.findByPath("taskA")?.doFirst {
    println("taskA findByPath")
}

tasks.named("taskA") {
    doLast {
        println("taskA named")
    }
}

文件操作

open class WriteFileTask : DefaultTask() {
    //任务输入参数
    @Input
    var text = ""

    //任务输出文件
    @OutputFile
    var outputFile: File? = null

    //任务运行时调用的方法
    @TaskAction
    fun writeText() {
        outputFile?.createNewFile()
        outputFile?.writeText(text)
    }

}

tasks.register("writeFileTask", WriteFileTask::class) {
    text = "content"
    outputFile = File(projectDir, "myFile.txt")
}

如果你看到了这里,觉得文章写得不错就给个赞呗?
更多Android进阶指南 可以扫码 解锁更多Android进阶资料


在这里插入图片描述
敲代码不易,关注一下吧。ღ( ´・ᴗ・` )

  • 30
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值