Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • The solution needs to support "Alternative Resources", aka overriding strings for other languages. (http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources)
  • The solution should be able to override values that are in the original (default) strings.xml file.
like image 256
treesAreEverywhere Avatar asked Feb 08 '16 15:02

treesAreEverywhere


People also ask

What happens during Gradle build?

Gradle Builds and Android StudioThe build system allows you to define flexible custom build configurations. Each build configuration can define its own set of code and resources while reusing the parts that are common to all versions of your app. Gradle and the Android plugin run independent of Android Studio.

What is the use of build Gradle file in Android?

The top-level build.gradle file, located in the root project directory, defines dependencies that apply to all modules in your project. By default, the top-level build file uses the plugins block to define the Gradle dependencies that are common to all modules in the project.

What type of file is build Gradle?

gradle files are the main script files for automating the tasks in an android project and are used by Gradle for generating the APK from the source files.


1 Answers

Here's a solution where your strings are modified via an external properties 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.

like image 102
lase Avatar answered Oct 23 '22 21:10

lase