根据buildType使用gradle覆盖资源

时间:2014-01-16 10:43:21

标签: android gradle android-studio android-gradle build.gradle

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

我知道since Android Gradle Plugin 0.7.+有可能拥有一个变体特定的源文件夹。 但我的应用程序有很多风格,我不想添加额外的变体特定文件夹。

更新2014-01-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定义一个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']
        }
    }
    

3 个答案:

答案 0 :(得分:18)

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

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

一些建议:

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

答案 1 :(得分:6)

我不相信您需要自定义构建脚本才能实现您的目标。根据我对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

所以我相信你只需在src / release / res。

中添加资源就可以达到你想要的效果

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

答案 2 :(得分:1)

如果有人偶然发现了这个

  buildTypes {
        debug{
            buildConfigField "String", "Your_string_key", '"yourkeyvalue"'
            buildConfigField "String", "SOCKET_URL", '"some text"'
            buildConfigField "Boolean", "LOG", 'true'
        }
        release {
            buildConfigField "String", "Your_string_key", '"release text"'
            buildConfigField "String", "SOCKET_URL", '"release text"'
            buildConfigField "Boolean", "LOG", 'false'

        }
    }

使用构建变体访问这些值:

 if(!BuildConfig.LOG)
      // do something with the boolean value

或者

view.setText(BuildConfig.yourkeyvalue);