【问题标题】:Replace word in strings.xml with gradle for a buildType将 strings.xml 中的单词替换为 buildType 的 gradle
【发布时间】:2017-04-12 03:24:42
【问题描述】:

我的项目有多个本地化版本。
现在我必须为不同的 buildTypes 替换所有 strings.xml 文件中的某个单词。例如,假设我有这个:

<string>My name is Bill</string>
<string>Bill is on duty today</string>

在另一个 buildType 中我需要有

<string>My name is Will</string>
<string>Will is on duty today</string>

我该怎么做(可能通过 Gradle)?

【问题讨论】:

  • 使用风味。通过阅读this
  • &lt;string&gt;My name is %s&lt;/string&gt; &lt;string&gt;%s is on duty today&lt;/string&gt; ... getString(id, "Bill");
  • @Selvin,谢谢,但我知道这种方式,无法使用此解决方案

标签: android gradle preprocessor


【解决方案1】:

您可以在 build.gradle 中执行以下操作,但仅适用于该特定字符串资源。

resValue "string", "&lt;string_name&gt;", string_value

【讨论】:

  • 这需要我在配置中添加所有使用过的&lt;string_name&gt; 字符串,对吧?
  • @VladMatvienko 是的,不幸的是......在strings.xml中的其他字符串资源中也不能包含对特定字符串资源的引用(至少作为字符串的部分组件)
  • 好的,谢谢,但是这个解决方案会花费太多时间,而且我知道其他更快但很难实现 TextView 的解决方案,它将任何 Bill 单词替换为 Will 单词。但如前所述,它很难看,我更喜欢在strings.xml 上使用一些预处理
【解决方案2】:

好的,找到了正确的解决方案,这不是解决方法: 对于所需的buildType,添加以下内容

    applicationVariants.all { variant ->
    variant.mergeResources.doLast {
        def dir = new File("${buildDir}/intermediates/res/merged/${variant.dirName}")  //iterating through resources, prepared for including to APK (merged resources)
        println("Resources dir " + dir)
        dir.eachFileRecurse { file ->
            if(file.name.endsWith(".xml")) { //processing only files, which names and with .xml
                String content = file.getText('UTF-8')
                if(content != null && content.contains("Bill")) {
                    println("Replacing name in " + file)
                    content = content.replace("Bill", "Will")  //replacing all Bill words with Will word in files
                    file.write(content, 'UTF-8')
                }

            }
        }
    }

【讨论】:

    【解决方案3】:

    这里的答案不再适用于最新的 android 构建工具,但这是一个适合我的新版本。

    android.applicationVariants.all { variant ->
        variant.mergeResources.doFirst {
             variant.sourceSets.each { sourceSet ->
                sourceSet.res.srcDirs = sourceSet.res.srcDirs.collect { dir ->
                    def relDir = relativePath(dir)
                    copy {
                        from(dir)
                        include '**/*.xml'
                        filteringCharset = 'UTF-8'
                        filter {
                            line -> line
                                    .replace('Bill', 'Will')
                        }
                        into("${buildDir}/tmp/${variant.dirName}/${relDir}")
                    }
                    copy {
                        from(dir)
                        exclude '**/*.xml'
                        into("${buildDir}/tmp/${variant.dirName}/${relDir}")
                    }
                    return "${buildDir}/tmp/${variant.dirName}/${relDir}"
                }
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      在您的应用程序(模块,而不是项目)的 build.gradle 目录中创建文件 gradle.properties。在这个应用程序中放置字符串,如 GOOGLE_MAPS_API_KEY = ishufhiaushdiasdh

      在 build.gradle 文件的 buildTypes 部分中添加字段“buildConfigField”。它看起来像:

      buildTypes {
              debug {
                  buildConfigField "String", "GOOGLE_MAPS_API_KEY", String.format("\"%s\"", GOOGLE_MAPS_API_KEY)
                  minifyEnabled false
                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
              }
              release {
                  buildConfigField "String", "GOOGLE_MAPS_API_KEY", String.format("\"%s\"", GOOGLE_MAPS_API_KEY)
                  minifyEnabled false
                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
              }
          }
      

      编译项目后,您会在 BuildConfig 类中找到生成的静态字符串值。

      【讨论】:

      • 这样我就可以在 JAVA 代码中使用该字段,但不能在 strings.xml 中使用,对吧?
      • 我目前也对 URL 使用这种方法
      【解决方案5】:

      为什么不直接使用动态字符串格式:

      <string name="my_message">%1$s is on duty today</string>
      

      在一个构建变体中:

      <string name="name">Bill</string>
      

      在另一个构建变体中:

      <string name="name">Will</string>
      

      在您的代码中:

      String text = String.format(getResources().getString(R.string.my_message), getResources().getString(R.string.name));
      

      【讨论】:

      • 我知道这个解决方案,但我不能使用它,因为它需要很长时间,并且可能会在迁移过程中产生错误。
      【解决方案6】:

      一种解决方案,虽然不是在所有情况下都适用,但是使用带有filter 指令的Copy 任务:

      task replace (type: Copy) {
         from "sources" {
            include "srcStrings.xml"
            filter { line -> line.replaceAll("Will", "Bill") }
         }
         into "strings.xml"
      }
      

      【讨论】:

        【解决方案7】:

        在处理这些行时,您应该观察使用replace() 和replaceAll() 获得的结果。并考虑到要处理的文件的绝对目录存在(不一定在res.srcDirs中)

        sourceSets {
            flavor {
        
                println res.srcDirs
        
                task testA() {
        
                    def relativeDirFile = 'src/flavor/res'
                    def file = "${relativeDirFile}/values/strings.xml"
                    def absoluteDirFile = "${rootDir}/module/${file}"
        
                    def buildDirToCopy = "${buildDir}/tmp/${relativeDirFile}/values"
        
                    copy {
                            from(absoluteDirFile)
                            filter {
                                String line ->
                                    println line
        
                                    line.replace("(.*)", line)  // To keep the line
                                    // OR
                                    line.replaceAll("(.*)", "") // To erase the line
                            }
                            into(buildDirToCopy)
                    }
        
                    res.srcDirs += (buildDirToCopy + "/strings.xml")
                    
                    // Check the directories that were included in the flavor.
                    println res.srcDirs
                }
        
            }
        }
        

        最后你可以extract the task 进入另一个 gradle 文件


        我也建议加深对regex的使用。

        GL

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-29
          • 1970-01-01
          • 2020-09-01
          • 1970-01-01
          相关资源
          最近更新 更多