2014-01-16 86 views
22

我想用resdle重写res/strings.xml中的一些字符串。根据buildType覆盖gradle资源

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

UPDATE 2014年1月17日

我想详细:

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

所以我尝试了另一个解决方案SOLUTION_2(只是合并正确的资源)根据this GitHub project of shakalaca。我认为这种方式更优雅,我仍然有优势,只是改变一个地方的变量!

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

我所做的在AS 0.4.2:

  • build.gradle我试图重写字符串 “Hello World” 到“越权”(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" 
        } 
    } 
    

复制和筛选任务工作正常,但我无法将“新”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'] 
        } 
    } 
    
+6

这一般只是不是一个很好的主意。如果您尝试在构建系统中执行重要的体操操作来修改资源,那么整个项目的维护和调试将非常困难。这将会非常脆弱,因为对该插件的更改可能会破坏它,或者对Android Studio的更改可能会使其无法使用。这是值得发布的问题,解释你到底想要完成什么,并列出你考虑的方法,包括这一个。 –

+0

感谢您的回答。我编辑了我的问题,并详细解释了我想要的内容。我想我为我的问题找到了一个很好的解决方案(SOLUTION_2)! – owe

+0

斯科特是对的:)我已经实施了solution_1,一年后我用更新的IDE返回了我的项目,更新了插件,它全部坏掉了。 –

回答

18

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

尤其是如果您只是在学习Android-Gradle项目的细节(而且它是如此新以至于我们都是),那么最好尽量使用内置于系统中的功能,然后再考虑外框。

一些建议:

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

现在有可能通过DSL生成资源值:https://plus.google.com/109385828142935151413/posts/UVKA58MZV3J。只是为了兴趣:应该像'BuildConfig'机制一样工作吗?我只是试过这个 - gradle没有抛出任何异常,但我找不到资源值。 – owe

+0

这是值得发布的,作为一个单独的问题,你正在使用的代码。我会upvote它;-) –

+0

是的...你说得对。我会在接下来的几天写一个新的问题。感谢您的赞扬:) – owe

5

我不相信你需要定制构建脚本来达到你想要的。根据我的阅读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。

+0

非常好! IDE甚至建议在创建资源文件之前选择构建类型。谢谢 – Viktor

0

如果有人偶然发现了这个

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); 
+1

这增加了一个字符串常量,但不是像OP想要的字符串资源。例如,您可能需要一个资源来引用Manifest或xml文件。 – sorianiv