草庐IT

android - 根据 buildType 用 gradle 覆盖资源

coder 2023-06-07 原文

我想用 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, packageNameSuffixversionNameSuffixsigningConfigzipAlignrunProguardproguardFile 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/

有关android - 根据 buildType 用 gradle 覆盖资源的更多相关文章

  1. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  2. ruby - 无法覆盖 irb 中的 to_s - 2

    我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  5. ruby - 覆盖相似的方法,更短的语法 - 2

    在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

  6. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  7. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

    我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

  8. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  9. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  10. ruby - 如何根据长度将路径数组转换为嵌套数组或散列 - 2

    我需要根据字符串路径的长度将字符串路径数组转换为符号、哈希和数组的数组给定以下数组:array=["info","services","about/company","about/history/part1","about/history/part2"]我想生成以下输出,对不同级别进行分组,根据级别的结构混合使用符号和对象。产生以下输出:[:info,:services,about:[:company,history:[:part1,:part2]]]#altsyntax[:info,:services,{:about=>[:company,{:history=>[:part1,:pa

随机推荐