我想用 gradle 覆盖我的 res/strings.xml 中的一些字符串。
我知道 since Android Gradle Plugin 0.7.+有可能有一个变体特定的源文件夹。 但是我的应用程序有很多口味,我不想添加额外的变体特定文件夹。
2014 年 1 月 17 日更新
我想要的详细信息:
我的资源中有一些变量仅取决于 buildType(例如“release”)。 首先,我认为我的 SOLUTION_1(资源合并后覆盖数据)很好,因为如果我必须更改这些变量,我只需在 build.config 中更改它们(只有一个地方)。 但正如 Scott Barta 在下面的评论中所写,有一些很好的理由说明这个解决方案不是一个好主意。
所以我尝试了另一个基于 this GitHub project of shakalaca 的解决方案 SOLUTION_2(只需合并正确的资源) .我认为这种方式更优雅,我仍然有优势,只需在一个位置更改变量!
SOLUTION_1(资源合并后覆盖数据):
我在 AS 0.4.2 中做了什么:
在
build.gradle
我尝试将字符串“Hello World”覆盖为“OVERRIDE”(based on my answer at this post):android.applicationVariants.all{ variant -> // override data in resource after merge task variant.processResources.doLast { overrideDataInResources(variant) } } def overrideDataInResources(buildVariant){ copy { // *** SET COPY PATHS *** try { from("${buildDir}/res/all/${buildVariant.dirName}") { // println "... FROM: ${buildDir}/res/all/${buildVariant.dirName}" include "values/values.xml" } } catch (e) { println "... EXCEPTION: " + e } into("${buildDir}/res/all/${buildVariant.dirName}/values") // println "... INTO: ${buildDir}/res/all/${buildVariant.dirName}/values" // --- override string "hello_world" filter { String line -> line.replaceAll("<string name=\"hello_world\">Hello world!</string>", "<string name=\"hello_world\">OVERRIDE</string>"); } // *** SET PATH TO NEW RES *** buildVariant.processResources.resDir = file("${buildDir}/res/all/${buildVariant.dirName}/values/values/values.xml") // println "... NEW RES PATH: " + "${buildDir}/res/all/${buildVariant.dirName}/values/values/values.xml" } }
复制和过滤任务工作正常,但我无法将"new"values.xml 设置为字符串资源。
SOLUTION_2(只需合并正确的资源)
- 为特定的 buildType 定义一个风格(例如“releaseRes”)
将此资源与您想要构建的风格合并:
android.applicationVariants.all{ variant -> variant.mergeResources.doFirst{ checkResourceFolder(variant) } } def checkResourceFolder(variant){ def name = variant.name; if(name.contains("Release")){ android.sourceSets.release.res.srcDirs = ['src/releaseRes/res'] android.sourceSets.flavor1.res.srcDirs = ['src/flavor1/res'] } }
最佳答案
您应该努力想出一个不涉及在构建文件中编写任何自定义代码的解决方案,尤其是那些通过动态重新分配源集来完成棘手事情的代码。自定义 Gradle 代码编写起来有点古怪,而且难以调试和维护。新的构建系统非常强大,并且已经具有大量的灵 active ,而且您很可能已经可以做您想做的事了;这只是学习如何做的问题。
特别是如果您只是了解 Android-Gradle 项目的来龙去脉(而且我们都是新事物),最好先尝试使用系统内置的功能,然后再跳出框框思考。
一些建议:
- 您不太可能需要根据构建类型改变资源。 Android-Gradle 中的构建类型应该类似于调试或发布,区别在于可调试性、编译器优化或签名;构建类型应该在功能上彼此等效。如果您查看 properties you can set on a build type through the Groovy DSL ,可以看到 Intent :
debuggable
,jniDebugBuild
,renderscriptDebugBuild
,renderscriptOptimLevel
,packageNameSuffix
、versionNameSuffix
、signingConfig
、zipAlign
、runProguard
、proguardFile
、proguardFiles
。 - 如果您仍然认为要根据构建类型改变资源,那么在当前的构建系统中已经有一种简单的方法可以做到这一点。您可以拥有一个特定于构建类型的资源目录,将您的资源放在那里,构建系统中的资源合并将在构建时为您处理好事情。这是 Android/Gradle 中的强大功能之一。见 Using Build Flavors - Structuring source folders and build.gradle correctly了解如何使这项工作发挥作用。
- 如果您想根据构建类型改变某些内容并且您的需求非常快速和简单,您可能希望在 Java 代码中而不是在资源中而不是在构建系统中进行切换。
BuildConfig
机制可用于此类事情——它是一个 Java 类,它根据调试/发布构建状态定义DEBUG
标志,您可以添加自己的自定义 Java来自不同构建类型的代码来做更有意义的事情。BuildConfig
旨在允许构建类型之间存在小的功能差异,适用于调试构建可能希望执行一些浪费操作以协助开发的情况,例如进行更广泛的数据验证或创建更详细的调试日志记录,那些浪费的东西最好从发布版本中优化出来。话虽如此,它可能是做你想做的事情的合适机制。 - 考虑为您目前使用的构建类型使用 flavor 。从概念上讲, flavor 有点像构建类型,因为它是可以构建的应用程序的另一种变体;构建系统将创建 flavor 与构建类型的矩阵,并且可以构建所有组合。但是, flavor 解决了不同的用例,其中不同的 flavor 共享大多数代码,但可能具有显着的功能差异。一个常见的例子是您的应用程序的免费与付费版本。由于您的应用程序的不同变体中的不同资源代表不同的功能,这可能表明需要不同的风格。 flavor 可以有不同的资源目录,在构建时以与构建配置相同的方式合并;有关详细信息,请参阅上面链接的问题。
关于android - 根据 buildType 用 gradle 覆盖资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21159484/