Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace strings resources with Android Gradle

I made a new app with gradle in Android Studio, and now I need to make about 10 versions with different package names and values in resources. I made custom flavors as in example and want to replace some strings in this custom flavors with custom values. I found example like this:

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

But i don't know where to put it. As i understand i need to put it into separate task, but how to make this task called by IDE?

Also i need to replace few variables inside Java classes and Content Provider's auth, maybe i need to do this by copy files into flavor1 folder and let gradle to merge it, but it seems like wrong solution to store many copies of files with difference in one line... Maybe i need to user some other solution for all this?

Here is 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"
        }

    }

}
like image 669
itspers Avatar asked Jun 24 '13 12:06

itspers


People also ask

How do I change the gradle path in Android Studio?

To change its path go to this path File > Settings... > Build, Execution, Deployment > Gradle In the Global Gradle settings Change Service directory path to what you want. Save this answer.

What is Android plugin for Gradle?

The Android Gradle plugin (AGP) is the official build system for Android applications. It includes support for compiling many different types of sources and linking them together into an application that you can run on a physical Android device or an emulator.


2 Answers

I had a similar problem. I wanted to add the Jenkins build number to the strings that get merged from strings.xml. Here's my solution as of Android Gradle plugin 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')
        }
    }
}

You might want to hook into a different Gradle task depending on what you want to do. Take a look at the tasks that are part of the Android build to figure that out.

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

UPDATE: At some point, the Android Gradle plugin changed the way to iterate through application variants keyword from each to all. My answer has been updated to reflect the change, but try switching to each if this code doesn't print anything to the console.

like image 81
goldierox Avatar answered Sep 24 '22 09:09

goldierox


I was trying to get similar functionality as Maven resource filtering. This is what I came up with. My solution could use some changes to be more robust (i.e. pulling from a properties file, etc).

My example just shows how to replace a single value, which is all that I needed. The variables follow the ${some.property} convention. This solution also works with product flavors that have their own resource files.

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()
}

Example in strings.xml

 ...
 <string name="app_version">${app.version}</string>
 ...
like image 42
Tom Bollwitt Avatar answered Sep 23 '22 09:09

Tom Bollwitt