Ionut Negru
Ionut Negru

Reputation: 6314

Android build gradle - replace string resource value

I have an special case where I need to override google map key string variable when building with Jenkins. I have setup an special structure like this:

  • debug
    • res
      • value
        • google_maps_api.xml
  • main
    • res
      • value
        • google_maps_api.xml

Thus, in the main res file I put the release API key and in the debug res file I put the debug API key (for the machine I'm working on - generated for the debug.keystore of Android).

In the build gradle file I have this basic logic for creating an string resource based on what was setup on Jenkins environment:

String googleMapApiKey = System.env.MAP_API_KEY;
...
android {
    ...
    buildTypes {
        ...
        debug {
             if (null != googleMapApiKey && !googleMapApiKey.equals("null")) {
                resValue "string", "google_maps_key", googleMapApiKey
            }
        }
        ...
    }
    ...
}

the xml file contains this:

<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">
    MY_DEBUG_API_KEY
</string>

I know the issue is because of the preserve flag of the string resource, but if remove that there are chances things get messed up and to loose that string resource. Is there an way I can replace the value of the actual string resource instead of just creating a new one in the build gradle file?

I was just thinking that an solution can also be to exclude that file when I'm using the value from Jenkins environment, but I do not know if it is doable with android gradle system. Does anyone know if this is doable and more important, how?

LE:

It seemed I had to move the res file from the main folder into the release one. Thus I have the following structure now:

  • debug
    • res
      • value
        • google_maps_api.xml
  • release
    • res
      • value
        • google_maps_api.xml

For now, it seems to be working like this.

LLE: The method from above doesn't work, I was fast on the conclusions. It seems the value from the xml file is still used, even if I declared the same(at least as name) in gradle script.

Upvotes: 2

Views: 3252

Answers (1)

Ionut Negru
Ionut Negru

Reputation: 6314

As an workaround for this I have implemented the following logic:

  • I removed google_maps_api.xml from release folder
  • I have created an custom method which loads an property from local.properties:

    /**
     * Get Google Map API Key which should be used by google map services.
     * <br/>
     * Note that this key should not be used when an key is available from Jenkins as most probably debug.keystore is
     * different than the one on your machine.
     *
     * @return the value of your local Google Map API Key
     */
    def getLocalGoogleMapApiKey() {
        Properties properties = new Properties()
        properties.load(project.rootProject.file('local.properties').newDataInputStream())
        def localMalKey = properties.getProperty('google.map.apiKey')
        if (localMalKey == null) {
            // Throw an exception if the property wasn't setup for this
            throw new GradleException(
                    "Google Map API Key property not found. Define your debug Google Map API Key [google.map.apiKey] in " +
                            "your local.properties file! E.g.: google.map.apiKey=YOUR_GOOGLE_MAP_API_KEY")
        }
    
        return localMalKey
    }
    
  • I have added the following property in local.properties file

    google.map.apiKey=MY_API_KEY
    
  • I have added the following logic in the build.gradle:

    ...
    // Google Map API Key - from Jenkins or from local
    String googleMapApiKey = System.env.MAP_API_KEY ?: getLocalGoogleMapApiKey();
    ...
    android {
        ...
        buildTypes {
            ...
            debug {
                /* Create a string resource which will be used in AndroidManifest.xml file (from Jenkins or local)*/
                resValue "string", "google_maps_key", googleMapApiKey
                println(">>>>>>>>> Google Map API Key: " + googleMapApiKey)
            }
            ...
        }
        ...
    }
    

I've chosen this solution, because of the following reasons:

  • Each user can set it's own API KEY for debugging (local.properties file won't affect other developers as it will never go on the repository)
  • Jenkins can change it's key at any time without affecting the project or any developer
  • There is no need to alter the structure of the project or mess around with it's resource
  • The method is safe to use by anyone and it will throw a nice error if anyone didn't setup the property correctly

I hope this helps others that have an similar issue:

Upvotes: 6

Related Questions