Custom Tasks trong Gradle
Gradle Tasks là đơn vị công việc cơ bản trong Gradle. Ngoài các tasks được cung cấp bởi plugins (như assembleDebug), bạn có thể tạo custom tasks để tự động hóa các công việc lặp đi lặp lại.
Giới thiệu về Gradle Tasks
Mỗi task trong Gradle thực hiện một công việc cụ thể và có thể phụ thuộc vào các tasks khác.
Xem danh sách tasks
# Tất cả tasks
./gradlew tasks
# Tasks với mô tả
./gradlew tasks --all
# Tasks của module cụ thể
./gradlew :app:tasksTasks phổ biến
| Task | Mô tả |
|---|---|
assembleDebug | Build APK debug |
assembleRelease | Build APK release |
bundleRelease | Build AAB release |
clean | Xóa build outputs |
test | Chạy unit tests |
connectedAndroidTest | Chạy instrumented tests |
lint | Chạy lint checks |
Tạo Custom Task đơn giản
Task cơ bản
// build.gradle.kts (module)
tasks.register("hello") {
group = "custom"
description = "A simple hello task"
doLast {
println("Hello from Gradle!")
}
}Chạy task:
./gradlew helloTask với doFirst và doLast
tasks.register("greeting") {
doFirst {
println("Preparing to greet...")
}
doLast {
println("Hello, World!")
}
doLast {
println("Goodbye!")
}
}📝 Lưu ý:
doFirstchạy trước,doLastchạy sau. Có thể có nhiềudoLastblocks và chúng chạy theo thứ tự khai báo.
Task Dependencies
dependsOn
Task phụ thuộc vào task khác:
tasks.register("buildAll") {
group = "build"
description = "Build all variants"
dependsOn("assembleDebug", "assembleRelease")
}finalizedBy
Task chạy sau khi task khác hoàn thành:
tasks.register("deploy") {
doLast {
println("Deploying...")
}
}
tasks.register("notify") {
doLast {
println("Deployment complete! Notifying team...")
}
}
tasks.named("deploy") {
finalizedBy("notify")
}mustRunAfter / shouldRunAfter
Xác định thứ tự khi cả hai tasks được yêu cầu:
tasks.register("taskA") {
doLast { println("A") }
}
tasks.register("taskB") {
mustRunAfter("taskA")
doLast { println("B") }
}
// ./gradlew taskB taskA → prints "A" then "B"Task với Inputs và Outputs
Gradle sử dụng inputs/outputs để xác định task có cần chạy lại hay không (incremental builds).
Ví dụ: Copy task
tasks.register<Copy>("copyDocs") {
group = "documentation"
description = "Copy documentation to output"
from("docs/")
into(layout.buildDirectory.dir("documentation"))
include("*.md", "*.txt")
exclude("**/draft/**")
}Ví dụ: Task với inputs/outputs tùy chỉnh
abstract class GenerateVersionFile : DefaultTask() {
@get:Input
abstract val versionName: Property<String>
@get:Input
abstract val versionCode: Property<Int>
@get:OutputFile
abstract val outputFile: RegularFileProperty
@TaskAction
fun generate() {
val content = """
version.name=${versionName.get()}
version.code=${versionCode.get()}
build.time=${System.currentTimeMillis()}
""".trimIndent()
outputFile.get().asFile.writeText(content)
}
}
tasks.register<GenerateVersionFile>("generateVersionInfo") {
group = "build"
versionName.set("1.0.0")
versionCode.set(1)
outputFile.set(layout.buildDirectory.file("version.properties"))
}Task thực tế
1. Clean và Build
tasks.register("cleanBuild") {
group = "build"
description = "Clean and build release APK"
dependsOn("clean", "assembleRelease")
tasks.findByName("assembleRelease")?.mustRunAfter("clean")
}2. Print Build Info
tasks.register("printBuildInfo") {
group = "help"
description = "Print build information"
doLast {
println("=== Build Info ===")
println("Gradle version: ${gradle.gradleVersion}")
println("JVM version: ${System.getProperty("java.version")}")
println("OS: ${System.getProperty("os.name")}")
println("Project: ${project.name}")
println("Build directory: ${layout.buildDirectory.get()}")
}
}3. Check Dependencies
tasks.register("checkOutdatedDeps") {
group = "verification"
description = "Check for outdated dependencies"
doLast {
exec {
commandLine("./gradlew", "dependencyUpdates", "-Drevision=release")
}
}
}4. Generate Build Report
tasks.register("generateBuildReport") {
group = "reporting"
description = "Generate a build report"
val reportDir = layout.buildDirectory.dir("reports/custom")
outputs.dir(reportDir)
doLast {
val reportFile = reportDir.get().file("build-report.md").asFile
reportFile.parentFile.mkdirs()
reportFile.writeText("""
# Build Report
- Date: ${java.time.LocalDateTime.now()}
- Project: ${project.name}
- Gradle: ${gradle.gradleVersion}
## Modules
${rootProject.subprojects.joinToString("\n") { "- ${it.name}" }}
""".trimIndent())
println("Report generated: ${reportFile.absolutePath}")
}
}5. APK Size Check
tasks.register("checkApkSize") {
group = "verification"
description = "Check APK size"
dependsOn("assembleRelease")
doLast {
val apkDir = layout.buildDirectory.dir("outputs/apk/release").get()
val apkFiles = apkDir.asFile.listFiles { file ->
file.name.endsWith(".apk")
}
apkFiles?.forEach { apk ->
val sizeMB = apk.length() / (1024.0 * 1024.0)
println("${apk.name}: %.2f MB".format(sizeMB))
if (sizeMB > 100) {
logger.warn("⚠️ APK size exceeds 100MB!")
}
}
}
}Sử dụng Plugin để tổ chức Tasks
Khi có nhiều custom tasks, nên tổ chức chúng trong một plugin:
buildSrc Plugin
- Tạo thư mục
buildSrc/:
buildSrc/
├── build.gradle.kts
└── src/main/kotlin/
└── CustomTasksPlugin.ktbuildSrc/build.gradle.kts:
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}CustomTasksPlugin.kt:
import org.gradle.api.Plugin
import org.gradle.api.Project
class CustomTasksPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("hello") {
group = "custom"
doLast {
println("Hello from plugin!")
}
}
project.tasks.register("printModules") {
group = "custom"
doLast {
project.rootProject.subprojects.forEach {
println("Module: ${it.name}")
}
}
}
}
}- Apply trong
build.gradle.kts:
apply<CustomTasksPlugin>()Best Practices
1. Luôn định nghĩa group và description
tasks.register("myTask") {
group = "custom" // Giúp phân loại trong ./gradlew tasks
description = "What this task does" // Mô tả rõ ràng
}2. Sử dụng inputs/outputs cho caching
tasks.register("processData") {
inputs.file("data/input.json")
outputs.file(layout.buildDirectory.file("output.json"))
doLast {
// Process data
}
}3. Tránh logic nặng trong configuration phase
// ❌ Chạy trong configuration phase
tasks.register("bad") {
val result = heavyComputation() // Chạy mỗi lần sync
doLast { println(result) }
}
// ✅ Chạy trong execution phase
tasks.register("good") {
doLast {
val result = heavyComputation()
println(result)
}
}4. Sử dụng lazy configuration
tasks.register("lazyTask") {
// Property được evaluate lazily
val version = project.providers.gradleProperty("version")
doLast {
println("Version: ${version.get()}")
}
}Các Task Types có sẵn
| Type | Mô tả |
|---|---|
Copy | Copy files |
Delete | Delete files/directories |
Exec | Execute external command |
JavaExec | Execute Java class |
Zip | Create ZIP archive |
Jar | Create JAR file |
Test | Run tests |
// Delete task
tasks.register<Delete>("cleanGenerated") {
delete(layout.buildDirectory.dir("generated"))
}
// Exec task
tasks.register<Exec>("runScript") {
commandLine("bash", "scripts/deploy.sh")
}
// Zip task
tasks.register<Zip>("packageDocs") {
from("docs/")
archiveFileName.set("documentation.zip")
destinationDirectory.set(layout.buildDirectory.dir("archives"))
}📚 Tham khảo
Last updated on