Skip to content

Provider API

Provider API 是 Gradle 5+ 引入的核心 API,提供类型安全的懒加载值管理。

核心接口

Provider<T>          ← 只读的懒加载值
├── Property<T>      ← 可写的 Provider
│   ├── RegularFileProperty    ← 文件属性
│   ├── DirectoryProperty      ← 目录属性
│   └── ConfigurableFileCollection ← 文件集合
└── ProviderFactory  ← 创建各种 Provider 的工厂

创建 Provider

kotlin
// 通过 project.providers 创建
val stringProvider: Provider<String> = providers.provider { "Hello" }
val fileProvider = providers.fileContents(layout.projectDirectory.file("version.txt")).asText
val envProvider = providers.environmentVariable("ENV_VAR")
val propProvider = providers.gradleProperty("myProp")

// 通过 layout 创建文件 Provider
val buildFile = layout.buildDirectory.file("output.jar")
val buildDir = layout.buildDirectory.dir("reports")

// 通过 ObjectFactory 创建
abstract class MyTask @Inject constructor(objects: ObjectFactory) : DefaultTask() {
    val myProp: Property<String> = objects.property(String::class.java)
    val myFile: RegularFileProperty = objects.fileProperty()
}

转换 Provider

kotlin
val version: Provider<String> = providers.gradleProperty("version")

// map:转换类型
val majorVersion: Provider<Int> = version.map { it.split(".")[0].toInt() }

// flatMap:Provider<Provider<T>> → Provider<T>
val resolvedVersion = version.flatMap { v ->
    providers.provider { lookupVersion(v) }
}

// zip:合并两个 Provider
val appId: Provider<String> = group.zip(version) { g, v -> "$g:$v" }

// orElse:提供默认值
val safeVersion = version.orElse("0.0.0-SNAPSHOT")

// filter:条件过滤(不满足则 Provider 无值)
val releaseVersion = version.filter { !it.endsWith("SNAPSHOT") }

在自定义任务中使用

kotlin
abstract class GenerateReportTask : DefaultTask() {
    @get:Input
    abstract val reportTitle: Property<String>
    
    @get:InputDirectory
    abstract val sourceDir: DirectoryProperty
    
    @get:OutputFile
    abstract val reportFile: RegularFileProperty
    
    @TaskAction
    fun generate() {
        val title = reportTitle.get()
        val src = sourceDir.get().asFile
        val out = reportFile.get().asFile
        
        out.writeText("# $title\n\nSource: ${src.path}")
    }
}

tasks.register<GenerateReportTask>("generateReport") {
    reportTitle.set("My Report")
    reportTitle.set(providers.gradleProperty("reportTitle").orElse("Default Report"))
    sourceDir.set(layout.projectDirectory.dir("src"))
    reportFile.set(layout.buildDirectory.file("reports/report.md"))
}

Provider 链式配置(推荐模式)

kotlin
// 避免配置阶段的副作用
tasks.named<Jar>("jar") {
    // 懒加载:只在 jar 任务执行时计算版本
    archiveVersion.set(providers.gradleProperty("version").orElse("0.0.0"))
    
    // 懒加载:从文件读取
    archiveBaseName.set(
        providers.fileContents(layout.projectDirectory.file(".appname"))
            .asText
            .map { it.trim() }
            .orElse(project.name)
    )
}

下一步