Android - Gradle - 自定义任务开发流程及调用

284 阅读1分钟

一、基本任务创建方式

// build.gradle.kts
tasks.register("customTask") {
    group = "custom"           // 任务分组
    description = "自定义任务描述" // 任务描述
    
    doFirst {
        println("任务开始执行...")
    }
    
    doLast {
        println("任务执行完成...")
    }
}

二、任务类型定义

/**
 * 自定义任务类型
 */
abstract class CustomTask : DefaultTask() {
    // 1. 定义输入属性
    @get:Input
    abstract val inputParam: Property<String>
    
    // 2. 定义输出属性
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    
    // 3. 初始化
    init {
        group = "custom"
        description = "自定义任务"
    }
    
    // 4. 任务执行逻辑
    @TaskAction
    fun execute() {
        println("处理输入: ${inputParam.get()}")
        outputFile.get().asFile.writeText("处理结果")
    }
}

三、任务注册和配置

// build.gradle.kts

// 1. 简单任务注册
tasks.register("simpleTask") {
    doLast {
        println("简单任务执行")
    }
}

// 2. 类型化任务注册
tasks.register<CustomTask>("typeTask") {
    inputParam.set("测试输入")
    outputFile.set(layout.buildDirectory.file("output.txt"))
}

// 3. 依赖其他任务
tasks.register("dependentTask") {
    dependsOn("simpleTask")
    doLast {
        println("依赖任务执行")
    }
}

四、任务执行流程图

graph TD
    A[注册任务] --> B[配置任务]
    B --> C[执行任务]
    
    subgraph 配置阶段
        B --> B1[设置属性]
        B --> B2[设置依赖]
        B --> B3[设置输入输出]
    end
    
    subgraph 执行阶段
        C --> C1[doFirst]
        C1 --> C2[TaskAction]
        C2 --> C3[doLast]
    end

五、高级任务示例

/**
 * 复杂任务示例
 */
abstract class AnalyzeCodeTask : DefaultTask() {
    // 1. 输入目录
    @get:InputDirectory
    abstract val sourceDir: DirectoryProperty
    
    // 2. 输出报告
    @get:OutputFile
    abstract val reportFile: RegularFileProperty
    
    // 3. 配置选项
    @get:Input
    abstract val includeTests: Property<Boolean>
    
    // 4. 嵌套输入
    @get:Nested
    abstract val config: AnalysisConfig
    
    // 5. 增量任务支持
    @get:Incremental
    @get:PathSensitive(PathSensitivity.RELATIVE)
    @get:InputFiles
    abstract val sourceFiles: ConfigurableFileCollection
    
    @TaskAction
    fun execute(inputChanges: InputChanges) {
        // 检查是否增量执行
        if (inputChanges.isIncremental) {
            // 处理变化的文件
            inputChanges.getFileChanges(sourceFiles).forEach { change ->
                when (change.changeType) {
                    ChangeType.MODIFIED -> handleModifiedFile(change.file)
                    ChangeType.ADDED -> handleAddedFile(change.file)
                    ChangeType.REMOVED -> handleRemovedFile(change.file)
                }
            }
        } else {
            // 完整执行
            handleAllFiles()
        }
        
        // 生成报告
        generateReport()
    }
    
    private fun handleModifiedFile(file: File) {
        println("处理修改的文件: ${file.name}")
    }
    
    private fun handleAddedFile(file: File) {
        println("处理新增的文件: ${file.name}")
    }
    
    private fun handleRemovedFile(file: File) {
        println("处理删除的文件: ${file.name}")
    }
    
    private fun handleAllFiles() {
        println("处理所有文件")
    }
    
    private fun generateReport() {
        reportFile.get().asFile.writeText("分析报告")
    }
}

六、任务配置和使用

// build.gradle.kts

// 1. 注册任务
tasks.register<AnalyzeCodeTask>("analyzeCode") {
    // 2. 配置输入
    sourceDir.set(layout.projectDirectory.dir("src/main"))
    reportFile.set(layout.buildDirectory.file("report.txt"))
    includeTests.set(true)
    
    // 3. 配置源文件
    sourceFiles.from(fileTree("src/main") {
        include("**/*.kt", "**/*.java")
    })
    
    // 4. 配置分析选项
    config.apply {
        maxWarnings.set(10)
        severity.set("HIGH")
    }
}

// 5. 添加依赖关系
tasks.named("build") {
    dependsOn("analyzeCode")
}

七、任务调用方式

  1. 命令行调用
# 直接执行任务
./gradlew analyzeCode

# 带参数执行
./gradlew analyzeCode --include-tests=false

# 查看任务信息
./gradlew tasks --group=custom
  1. 代码中调用
// 其他任务中调用
tasks.register("composite") {
    dependsOn("analyzeCode")
    doLast {
        // 获取分析结果
        val report = tasks.named<AnalyzeCodeTask>("analyzeCode")
            .get().reportFile.get().asFile
        println("分析结果: ${report.readText()}")
    }
}

八、最佳实践

  1. 任务命名规范
tasks.register<CustomTask>("generateApiDocs") {
    group = "documentation"
    description = "生成API文档"
}
  1. 输入输出声明
abstract class DocumentationTask : DefaultTask() {
    @get:InputDirectory
    abstract val sourceDir: DirectoryProperty
    
    @get:OutputDirectory
    abstract val outputDir: DirectoryProperty
}
  1. 增量构建支持
@TaskAction
fun execute(inputChanges: InputChanges) {
    if (inputChanges.isIncremental) {
        // 增量处理
    } else {
        // 完整处理
    }
}
  1. 错误处理
tasks.register("safeTask") {
    doLast {
        try {
            // 任务逻辑
        } catch (e: Exception) {
            logger.error("任务执行失败", e)
            throw GradleException("任务执行失败: ${e.message}")
        }
    }
}

通过这些方式,我们可以:

  1. 创建自定义任务
  2. 配置任务属性
  3. 处理任务依赖
  4. 支持增量构建
  5. 优化构建性能

关键点:

  • 正确使用注解
  • 合理设置依赖
  • 支持增量构建
  • 做好错误处理