treesAreEverywhere February 2016

In an Android gradle build, change contents of strings.xml during build

I would like to be able to load the value of user-visible strings from res/values/strings.xml from our CMS (or some DB), during the gradle build.

E.g.

<string name="button_label">OK, do it</string>

Could be changed to

<string name="button_label">OK, do it now!</string>

... or whatever.

The idea being that the new value would be read AT BUILD TIME from our CMS, and then would get baked into the APK file. ( The motivation is to automate changes to app strings, so that any text from the app would be read from an existing CMS).

What's the best way to achieve this? Is it possible to generate/modify the resource files (e.g. strings.xml ) during build, just before they are used by the Android build system?


Adding some more requirements:

Answers


lase February 2016

Here's a solution where your strings are modified via an external propertise file. Not sure that this fits your requirement exactly, but it should get you off to a start.

I do something similar in my builds - I have some custom gradle tasks with this type of replacement called inside of their doFirst(). The regex here could probably use some polishing, and the input format may change per your requirement, but in a few local tests this seems to work for me.

ext.updateStrings = {
println("Changing strings!")
Properties props = new Properties()
props.load(new FileInputStream(file('cms.properties')))
def stringsFile = file("src/main/res/values/strings.xml")
def stringsText = stringsFile.getText()
for (p in props) {
    def pattern = Pattern.compile(String.format("%s\">.*<", p.key));
    def match = pattern.matcher(stringsText);
    match.find();
    println("found key " + p.key + ", replacing string with " + p.value)
    stringsText = match.replaceAll(String.format("%s\">%s<", p.key, p.value))
    stringsFile.write(stringsText)
    }
}

I keep my external properties/functions in a separate file (for instance common.gradle). In your build.gradle, you could add a custom task like so:

apply from: "common.gradle"
task updateStringsXml() {
    doFirst {
        updateStrings()
    }
}

Then, your gradle command might look like gradle updateStringsXml assembleRelease.

Post Status

Asked in February 2016
Viewed 3,254 times
Voted 10
Answered 1 times

Search




Leave an answer