【问题标题】:How to replace strings resources with Android Gradle如何用 Android Gradle 替换字符串资源
【发布时间】:2013-06-24 12:26:53
【问题描述】:

我在 Android Studio 中使用 gradle 制作了一个新应用,现在我需要制作大约 10 个版本,在资源中具有不同的包名称和值。我像示例一样制作了自定义风味,并希望用自定义值替换此自定义风味中的一些字符串。我找到了这样的例子:

filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: ['version': '2.2'])

但我不知道该放在哪里。据我了解,我需要把它放到单独的任务中,但是如何让这个任务被 IDE 调用?

我还需要替换 Java 类和 Content Provider 的身份验证中的几个变量,也许我需要通过将文件复制到 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"
        }

    }

}

【问题讨论】:

    标签: android gradle android-studio


    【解决方案1】:

    我遇到了类似的问题。我想将 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')
            }
        }
    }
    

    您可能希望根据您想要执行的操作挂钩到不同的 Gradle 任务。看看作为 Android 构建一部分的任务来解决这个问题。

    http://tools.android.com/tech-docs/new-build-system/user-guide

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

    【讨论】:

    • 我怀疑我研究过文件夹结构,在${buildDir} 中有一个文件夹rssource 文件夹` 和一个res 文件夹,我怀疑它们是相似的,但是为什么source/rs 是空的,虽然 ("${buildDir}/res/all/${variant.dirName}/values/values.xml")` 可以解决问题,但是修改 value-14.xml 怎么样?
    • @aelam,我相信rs 目录是用于 RenderScript,而res 文件夹是用于您的资源。如果您想修改“values-[API-level].xml”文件,您可以使用正则表达式或遍历该目录中的文件。我不知道如何摆脱我的头顶。我建议查看 Gradle 文档。 gradle.org/docs/current/userguide/working_with_files.html
    • 我设法在 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 有效,但并不理想。更多详情:twitter.com/ashughes88/status/929092362248130561
    【解决方案2】:

    我试图获得与 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:mergeDebugResources'的执行失败。 > 没有这样的属性:ExpandProperties 类:org.gradle.api.internal.file.copy.CopySpecWrapper_Decorated。你知道怎么处理它吗?
    • 你用的是什么版本的gradle?
    • 这不适用于 AAPT2,因为 .xml 文件在写入磁盘之前会被展平。见:issuetracker.google.com/issues/65220623
    【解决方案3】:

    这些链接可能会有所帮助:

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

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

    【讨论】:

    • 谢谢,但是如何定义这个任务以及如何在构建类型或风格中使用它?
    • @itspers 有关如何修改特定构建变体的更多信息,请参阅我的答案
    • 问题是'build/path/to/your/filtered/resources/' path 在哪里
    • 当你运行 gradle 脚本时,'build' 是在你的项目根目录生成的子目录; gradle clean 删除“构建”。
    • @aelam 此类构建工件的位置是您自己的选择,但遵循 gradle 约定会很方便。以上相对路径符号以build 开头,运行gradle 脚本后,您可以在$PROJECT_ROOT/build/path/to/filtered/resources 上找到过滤后的资源。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2016-09-24
      • 2013-10-23
      • 1970-01-01
      • 2013-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多