根据buildType使用gradle覆盖资源

owe*_*owe 23 android gradle android-studio build.gradle android-gradle-plugin

我想用gradle覆盖res/strings.xml中的一些字符串.

我知道,因为Android Gradle Plugin 0.7.+ theres可能有一个变种特定的源文件夹.但我的应用程序有很多口味,我不想添加额外的变体特定文件夹.

更新2014-01-17

我想要的详细信息:

我的资源中有一些变量只依赖于buildType(例如"release").首先,我认为我的SOLUTION_1(在资源合并后覆盖数据)很好,因为如果我必须更改这些变量,我只需要在build.config(只有一个地方)中更改它们.但正如Scott Barta在下面的评论中所写的那样,为什么这个解决方案不是一个好主意有一些很好的理由.

所以我尝试了另一个解决方案SOLUTION_2(只是合并正确的资源)基于shakalaca的这个GitHub项目.我认为这种方式更优雅,我仍然有一个优势就是在一个地方改变变量!

SOLUTION_1(在资源合并后覆盖数据):

我在AS 0.4.2中做了什么:

  • build.gradle我尝试将字符串"Hello World"覆盖为"OVERRIDE"(根据我在这篇文章中的回答):

    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"
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

复制和筛选任务工作正常,但我无法将"new"values.xml设置为字符串资源.

SOLUTION_2(只需合并合适的资源)

  • 为特定的buildType定义一个floavor(例如"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']
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

Sco*_*rta 18

您应该努力提出一种解决方案,该解决方案不涉及在构建文件中编写任何自定义代码,尤其是在动态重新分配源集时执行棘手操作的代码.自定义Gradle代码编写起来有点时髦,而且很难调试和维护.新的构建系统非常强大,已经具有很大的灵活性,很可能你已经可以做你想做的事了; 这只是学习方法的问题.

特别是如果你只是学习Android-Gradle项目的细节(而且它是如此新的,我们都是),最好在开箱即用之前尽力使用系统内置的功能.

一些建议:

  • 您不太可能需要根据构建类型更改资源.Android-Gradle中的构建类型应该类似于调试或发布,其区别在于可调试性,编译器优化或签名; 构建类型应该在功能上彼此相同.如果你看一下,你可以通过Groovy的DSL构建类型设置属性,你可以看到的意图:debuggable,jniDebugBuild,renderscriptDebugBuild,renderscriptOptimLevel,packageNameSuffix,versionNameSuffix,signingConfig,zipAlign,runProguard,proguardFile,proguardFiles.
  • 如果您仍然认为您希望根据构建类型更改资源,那么使用当前构建系统已经有了一种简单的方法.您可以拥有特定于构建类型的资源目录,将资源放在那里,构建系统中的资源合并将在构建时为您处理事情.这是Android/Gradle中的强大功能之一.请参阅使用构建风格 - 正确构建源文件夹和build.gradle,以获取有关如何使其工作的信息.
  • 如果您想根据构建类型改变某些内容,并且您的需求非常快速和简单,那么您可能希望使用Java代码而不是资源而不是构建系统进行切换.有这种BuildConfig机制 - 它是一个DEBUG基于调试/发布构建状态定义标志的Java类,您可以从不同的构建类型添加自己的自定义Java代码来执行更有意义的事情.BuildConfig用于允许构建类型之间的小功能差异,用于调试构建可能需要执行一些浪费操作以协助开发的情况,例如进行更广泛的数据验证或创建更详细的调试日志记录,并且这些浪费的事情最佳地优化了发布版本.话虽如此,它可能是一个适当的机制来做你想要的.
  • 考虑使用flavor来实现你现在使用的构建类型.从概念上讲,风味有点像构建类型,因为它是可以构建的应用程序的另一种变体; 构建系统将创建一个味道与构建类型的矩阵,并可以构建所有组合.但是,风格解决了不同的用例,其中不同的风格共享大多数代码但可能具有显着的功能差异.一个常见的例子是您的应用程序的免费版和付费版.因为应用程序的不同变体中的不同资源代表不同的功能,这可能表明需要不同的风格.Flavors可以有不同的资源目录,它们在构建时以与构建配置相同的方式合并; 请参阅上面链接的问题以获取更多信息.

  • 现在有可能通过DSL生成资源值:https://plus.google.com/109385828142935151413/posts/UVKA58MZV3J.只是为了感兴趣:这应该像`BuildConfig`机制一样吗?我刚试过这个 - gradle没有抛出任何Exception,但我找不到资源值. (2认同)

小智 7

我不相信你需要自定义构建脚本来实现你想要的.根据我对http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants的阅读; 当构建运行时,资源将从以下文件夹合并(如果存在);

src/[flavour][buildType]/res
src/[buildType]/res
src/[flavour]/res
src/main/res
Run Code Online (Sandbox Code Playgroud)

所以我相信你只需在src/release/res中添加资源就可以实现你想要的.

虽然您可以通过指定相关的sourceSets来调整文件夹名称.[type] .res.srcDirs如果您真的想要更改它们.