将 strings.xml 中的单词替换为 gradle 以获得 buildType

Replace word in strings.xml with gradle for a buildType

我有一个有多个本地化版本的项目。
现在我必须为不同的 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)?

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

resValue "string", "<string_name>", string_value

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

在 buildTypes 部分的 build.gradle 文件中添加字段 '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 中发现生成的值为静态字符串 class。

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

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

好的,找到了正确的解决方案,这不是解决方法: 对于所需的 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')
                }

            }
        }
    }

一种解决方案,虽然并非适用于所有情况,但使用带有 filter 指令的 Copy 任务:

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

此处的答案不再适用于最新的 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}"
            }
        }
    }
}

在处理线条时,您应该观察使用 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