如何用Android Gradle替换字符串资源

如何用Android Gradle替换字符串资源,android,gradle,android-studio,Android,Gradle,Android Studio,我在Android Studio中用gradle制作了一个新的应用程序,现在我需要在参考资料中用不同的包名和值制作大约10个版本。我制作了示例中的自定义风格,并希望用自定义值替换此自定义风格中的一些字符串。我发现这样的例子: filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: ['version': '2.2']) 但我不知道该把它放在哪里。据我所知,我需要将其放入单独的任务中,但如何使此任务由IDE调用呢 我还需要替换Java

我在Android Studio中用gradle制作了一个新的应用程序,现在我需要在参考资料中用不同的包名和值制作大约10个版本。我制作了示例中的自定义风格,并希望用自定义值替换此自定义风格中的一些字符串。我发现这样的例子:

filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: ['version': '2.2'])
但我不知道该把它放在哪里。据我所知,我需要将其放入单独的任务中,但如何使此任务由IDE调用呢

我还需要替换Java类和内容提供商的auth中的几个变量,也许我需要将文件复制到flavor1文件夹中,让gradle合并它,但在一行中存储不同文件的多个副本似乎是错误的解决方案。。。也许我需要使用其他解决方案来解决这一切

下面是build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.4.2'
    }
}
apply plugin: 'android'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    compile project(':JazzyListView')
    compile project(':ABS')
    compile project(':Volley')
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        versionCode 5
        versionName "3.0"
        minSdkVersion 8
        targetSdkVersion 17
    }

    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java']
            res.srcDirs = ['src/main/res']
        }
    }

    productFlavors {
        flavor1 {
            packageName "com.example.flavor1"               
        }

        flavor2 {
            packageName "com.example.flavor2"
        }

    }

}

在“src”文件夹中,创建与“main”文件夹具有相同层次结构的“flavor1”和“flavor2”文件夹。如果在main/res/values中有strings.xml,那么也可以在flavor1/res/values中执行,并在其中包含替换值。它可能在IDE中显示错误,但仍应生成并运行

以下链接可能会有所帮助:

我的过滤器定义使用正则表达式替换某些内容:

from('res/') {
    include '**/*.xml'
    filter {
        line -> line.replaceAll(/YOUR_REGEX_TO_REPLACE_SOMETHING/, 'REPLACED_RESULT_EXPRESSION')
    }
}
into 'build/path/to/your/filtered/resources/'

我也有类似的问题。我想将Jenkins构建编号添加到从strings.xml合并的字符串中。这是我从Android Gradle插件0.12开始的解决方案

// Insert the build number into strings.xml
android.applicationVariants.all{ variant ->
    variant.mergeResources.doLast{
        ext.env = System.getenv()
        def buildNumber = env.BUILD_NUMBER
        if (buildNumber != null) {
            File valuesFile = file("${buildDir}/intermediates/res/${variant.dirName}/values/values.xml")
            println("Replacing revision number in " + valuesFile)
            println("Build number = " + buildNumber)
            String content = valuesFile.getText('UTF-8')
            content = content.replaceAll(/devBuild/, buildNumber)
            valuesFile.write(content, 'UTF-8')
        }
    }
}
根据你想做的事情,你可能想加入一个不同的梯度任务。看看Android构建中的任务,就知道了


更新:在某个时候,Android Gradle插件改变了从每个应用程序变量关键字到所有应用程序变量关键字的迭代方式。我的答案已更新以反映更改,但如果此代码未将任何内容打印到控制台,请尝试切换到每个选项。

我试图获得与Maven资源筛选类似的功能。 这就是我想到的。我的解决方案可以使用一些更改来增强健壮性(例如,从属性文件中提取,等等)

我的示例只是展示了如何替换单个值,这就是我所需要的。变量遵循
${some.property}
约定。此解决方案还适用于具有自己的资源文件的产品风格

import org.apache.tools.ant.filters.*
...
android.applicationVariants.all{ variant ->
    // Perform resource filtering
    variant.mergeResources.doLast {
        filterResources(variant)
    }
}

def filterResources(buildVariant) {

    //Setup temp directory to filter the resources
    File resFiltered = file("${buildDir}/res/all/filtered/${buildVariant.dirName}")
    if(resFiltered.exists()){
        resFiltered.delete()
    }

    //Copy and filter the resources.
    copy {
        from(buildVariant.processResources.resDir) {
            include '**/*.xml'

            //Could be improved upon to pull from a properties file, etc.
            ant.properties['app.version'] = project.version

            filter(ExpandProperties, project: ant.project)

        }
        from(buildVariant.processResources.resDir) {
            exclude '**/*.xml'
        }

        into resFiltered

    }

    //Delete all the original resource files
    file(buildVariant.processResources.resDir).deleteDir()
    //Replace with the filtered ones.
    resFiltered.renameTo(file(buildVariant.processResources.resDir))
    //Delete the original 'filtered' directory
    file( "${buildDir}/res/all/filtered").deleteDir()
}
strings.xml中的示例

 ...
 <string name="app_version">${app.version}</string>
 ...
。。。
${app.version}
...

谢谢,但如何定义此任务以及如何在构建类型或风格中使用它?@itspers请参阅我的答案,以了解有关如何修改特定构建变量的更多信息问题是当运行gradle脚本时,
'build/path/to/your/filtered/resources/'路径在哪里?
在项目根目录上生成“build”子目录
gradle clean
删除“构建”。@aelam此类构建工件的位置由您自己选择,但遵循gradle约定会很方便。使用上面的相对路径表示法,从
build
开始,在运行gradle脚本后,您可以在
$PROJECT\u ROOT/build/path/to/filtered/resources
上找到筛选的资源。我怀疑我是否研究过
${buildDir}中的文件夹结构
sourcefolder`和
res
文件夹中有一个文件夹
rs
,我怀疑它们是否相似,但是为什么
source/rs
是空的,尽管(“${buildDir}/res/all/${variant.dirName}/values/values.xml”)可以解决问题,但是如何修改value-14.xml呢?@aelam,我相信
rs
目录用于RenderScript,而
res
文件夹用于您的资源。如果要修改“values-[API level].xml”文件,可能需要使用正则表达式或遍历该目录中的文件。我不知道怎样才能忘乎所以。我建议您查看Gradle文档。我设法在0.8中使用:File valuesFile=new File(${buildDir}/intermediates/res/${variant.dirName}/values/values.xml)实现了这一点,但它首先需要一个gradlew clean,以寻找更好的解决方案。@eski我认为您指的是Android Studio版本号,但是构建输出目录结构与Android Gradle插件绑定。但两者都是紧密配对的。我已将您的更新添加到我的答案中。仅供参考,此解决方案不再适用于Android Gradle插件3.0.0/AAPT2。原因是AAPT2改变了资源的处理和合并方式。当前的解决方法是禁用AAPT2或在生成之前修改资源。我已经验证了禁用AAPT2是可行的,尽管这并不理想。更多详细信息:您好,我在实现时遇到一些问题,我遇到异常:任务执行失败“:app:mergeDebugResources”。>没有这样的属性:ExpandProperties for class:org.gradle.api.internal.file.copy.CopySpecWrapper\u。你知道怎么处理它吗?你使用的是什么版本的gradle?这不适用于AAPT2,因为.xml文件在写入磁盘之前是扁平的。见: