Skip to Content

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:tasks

Tasks phổ biến

TaskMô tả
assembleDebugBuild APK debug
assembleReleaseBuild APK release
bundleReleaseBuild AAB release
cleanXóa build outputs
testChạy unit tests
connectedAndroidTestChạy instrumented tests
lintChạ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 hello

Task với doFirst và doLast

tasks.register("greeting") { doFirst { println("Preparing to greet...") } doLast { println("Hello, World!") } doLast { println("Goodbye!") } }

📝 Lưu ý: doFirst chạy trước, doLast chạy sau. Có thể có nhiều doLast blocks 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

  1. Tạo thư mục buildSrc/:
buildSrc/ ├── build.gradle.kts └── src/main/kotlin/ └── CustomTasksPlugin.kt
  1. buildSrc/build.gradle.kts:
plugins { `kotlin-dsl` } repositories { mavenCentral() }
  1. 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}") } } } } }
  1. 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

TypeMô tả
CopyCopy files
DeleteDelete files/directories
ExecExecute external command
JavaExecExecute Java class
ZipCreate ZIP archive
JarCreate JAR file
TestRun 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