如何在Android Gradle任务中注册生成的资源?

时间:2020-02-12 13:06:27

标签: android gradle android-gradle-plugin android-resources

我正在尝试在Gradle任务中生成一些Android资源。

我编写了一个任务,该任务分析输入文件,并将XML文件写到应用程序build目录下的位置。

app / build.gradle

import groovy.xml.MarkupBuilder


task generateSomeAppResources {
    ext.outputDir = new File(projectDir, "build/generated/res/values")
    doFirst {
        mkdir outputDir

        new File(outputDir, "generated.xml").withWriter { writer ->
            def destXml = new MarkupBuilder(new IndentPrinter(writer, "    ", true, true))
            destXml.setDoubleQuotes(true)
            def destXmlMkp = destXml.getMkp()
            destXmlMkp.xmlDeclaration(version: "1.0", encoding: "utf-8")
            destXmlMkp.comment("Generated at ${new Date()}")
            destXmlMkp.yield "\r\n"

            destXml.resources() {
                "string"("name": "generated_app_resource") {
                    destXmlMkp.yield("Some generated value for the app")
                }
            }
        }
    }
}

这很好,并且生成的输出看起来像我期望的那样。

generated.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Generated at Wed Feb 12 12:46:12 GMT 2020 -->
<resources>
    <string name="generated_app_resource">Some generated value for the app</string>
</resources>


尽管如此,我仍在努力让Android构建系统能够检测生成的文件。 Google's advice

使用BaseVariant.registerGeneratedResFolders()

编写一个任务,以根据需要输出输出生成的资源目录结构的任务。

但是关于registerGeneratedResFolders()的文档不存在。经过大量乏味的搜索之后,例如,在Play Services Plugin source中找到了一些示例用法,因此我尝试沿这些内容添加一些内容。

app / build.gradle

android.applicationVariants.all { variant ->
    def files = project.files(generateSomeAppResources.outputDir)
    files.builtBy(generateSomeAppResources)
    variant.preBuildProvider.configure { dependsOn(generateSomeAppResources) }
    variant.mergeResourcesProvider.configure { dependsOn(generateSomeAppResources) }
    variant.registerGeneratedResFolders(files)
}

但是我错过了一些东西。生成的资源在Android Studio中显示为紫色,这意味着IDE认为它存在...

enter image description here

...但是代码无法编译,并出现Unresolved reference: generated_app_resource错误。

我不知道要使Android构建系统获取这些资源需要什么魔咒。如何构建它?

2 个答案:

答案 0 :(得分:3)

要创建资源,android需要

1)在values文件夹上方的资源目录中,然后您可以根据需要添加所需的资源

2)指示构建过程在构建R.java

时添加生成的资源

因此,首先将构建资源任务配置为:

task generateSomeAppResources {
    ext.outputDir = new File(projectDir, "build/generated/res/custom/values")
    print("path is "+projectDir)
    doFirst {
        mkdir outputDir

        new File(outputDir, "strings.xml").withWriter { writer ->
            def destXml = new MarkupBuilder(new IndentPrinter(writer, "    ", true, true))
            destXml.setDoubleQuotes(true)
            def destXmlMkp = destXml.getMkp()
            destXmlMkp.xmlDeclaration(version: "1.0", encoding: "utf-8")
            destXmlMkp.comment("Generated at ${new Date()}")
            destXmlMkp.yield "\r\n"

            destXml.resources() {
                "string"("name": "generated_app_resource") {
                    destXmlMkp.yield("Some generated value for the app")
                }
            }
        }
    }
}

现在使用sourceSets(应用程序)中的build.gradle(如

)在构建过程中添加路径
android {
    //....
    sourceSets {
        main {
            res.srcDirs += [
                    'build/generated/res/custom',
            ]
        }
    }
}

此外,将任务添加为当前构建过程中的

gradle.projectsEvaluated {
    preBuild.dependsOn('generateSomeAppResources')
} // no need of `android.applicationVariants.all...` 

现在同步项目,它将按预期运行。

结果:

enter image description here

答案 1 :(得分:1)

有关如何使用BaseVariant.registerGeneratedResFolders

生成资源的示例
def generateResourcesTask = tasks.register("generateResources", GenerateResourcesTask)
android.libraryVariants.all { variant ->
    variant.registerGeneratedResFolders(
        project.files(generateResourcesTask.map { it.outputDir })
    )
}

使用tasks.register(...)project.files(...)TaskProvider.map(...)利用任务回避api,并自动连接任务相关性。 registerGeneratedResFolders还会自动将资源添加到源集,以便您可以在代码中引用生成的资源。

abstract class GenerateResourcesTask : DefaultTask() {

    // If you need inputs
    // @get:InputFiles
    // lateinit var inputs: FileCollection

    @get:OutputDirectory
    val outputDir = File(project.buildDir, "generated/res/regenerate/")

    private val outputFile = File(outputDir, "values/missingRes.xml")

    @TaskAction
    fun action() {
        val result = buildString {
            appendln(
                """
                <?xml version="1.0" encoding="utf-8"?>
                <resources>
                """.trimIndent()
            )

            appendln("""    <string name="test_string">Test string</string>""")

            appendln("</resources>")
        }

        outputFile.parentFile.mkdirs()
        outputFile.writeText(result)
    }
}

您可以在build.gradle文件或buildSrc中定义此任务类。 使用@OutputFile之类的注释可使您的任务递增。 有关更多信息,请参见gradle's documentation,以了解注释的用途和用法。您也可以使用Runtime API创建带有属性的任务。

相关问题