如何在AndroidGradle任务中注册生成的资源?
How to register generated resources in Android Gradle task?
我正在尝试在 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 是
to write a task that outputs a generated resource directory structure with whatever you need, use 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 认为它存在...
...但是代码无法编译并出现 Unresolved reference: generated_app_resource
错误。
我不知道需要什么魔法才能让 Android 构建系统获取这些资源。我如何构建它?
要创建资源,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")
}
}
}
}
}
现在在 build.gradle
(app) 中使用 sourceSets
在构建过程中添加路径,例如
android {
//....
sourceSets {
main {
res.srcDirs += [
'build/generated/res/custom',
]
}
}
}
此外,在当前构建过程中添加任务为
gradle.projectsEvaluated {
preBuild.dependsOn('generateSomeAppResources')
} // no need of `android.applicationVariants.all...`
现在同步项目,它将按预期工作。
结果:
有关如何使用 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
还会自动将资源添加到 sourceset,以便您可以在代码中引用生成的资源。
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 中定义此任务 class。
使用像 @OutputFile
这样的注释可以使你的任务增量。
有关注释的作用以及如何使用它们的更多信息,请查看 gradle's documentation. You can also use Runtime API 以创建具有属性的任务。
我正在尝试在 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 是
to write a task that outputs a generated resource directory structure with whatever you need, use 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 认为它存在...
...但是代码无法编译并出现 Unresolved reference: generated_app_resource
错误。
我不知道需要什么魔法才能让 Android 构建系统获取这些资源。我如何构建它?
要创建资源,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")
}
}
}
}
}
现在在 build.gradle
(app) 中使用 sourceSets
在构建过程中添加路径,例如
android {
//....
sourceSets {
main {
res.srcDirs += [
'build/generated/res/custom',
]
}
}
}
此外,在当前构建过程中添加任务为
gradle.projectsEvaluated {
preBuild.dependsOn('generateSomeAppResources')
} // no need of `android.applicationVariants.all...`
现在同步项目,它将按预期工作。
结果:
有关如何使用 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
还会自动将资源添加到 sourceset,以便您可以在代码中引用生成的资源。
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 中定义此任务 class。
使用像 @OutputFile
这样的注释可以使你的任务增量。
有关注释的作用以及如何使用它们的更多信息,请查看 gradle's documentation. You can also use Runtime API 以创建具有属性的任务。