Using Gradle has many cool features, the one that I really like is the ability to change configurations based on build type (release or debug).
Background
One of the headaches of building Internet enabled applications is pointing your application to a different API service based on the stage of development. For instance, for a QA build of a product I have had the need to point an application to a QA API Instance, or during initial development of APIs, to a development server. There are many ways to accomplish this, from reading a configuration file loaded on the device or changing a string resource to a new host. But I have started using my Gradle configurations to point my Android applications to different API host servers.
Common Configuration Switching
A common method for switching host configurations is a complicate if statements:
if (BuildConfig.Debug) {
… use host A
} else {
… use host B
}
Of course, using this approach has many downsides, one of which is ugly “if” statements scattered through out your code. And when you have multiple flavors of the product with different debug versus release host API’s, it can get really ugly.
Another method is to use string resources that are loaded per flavor of build. A debug resource string file could contain Host A URL, which Staging flavor could contain Host B URL. This keeps the complicated if statements to a simple string load. But now your URL’s are in different files, and maintaining the multiple files always leads to ‘which is getting loaded’, ‘what is the current host’, etc.
This is where Gradle configurations can help clean up the code, and to me the main benefit is there is one source of truth of the host configuration settings.
Gradle Setup
Here are the basic steps for setting up Gradle configurations. Within the application build.gradle file use the buildConfigField attribute. The build system will generate a special class called BuildConfig and adds these new fields.
Ex:
buildConfigField 'String', 'hostAPI', '"https://somehosst.com/rest/api"'
To specify different values for Release and Debug build types, add the different config fields within the buildTypes.
buildTypes {
release {
..
buildConfigField 'String', 'hostAPI', '"https://prod.somehost.com/rest/api"'
..
}</pre>
debug {
..
buildConfigField 'String', 'hostAPI', '"https://dev.somehost.com/rest/api"'
..
}
}
Then to reference the value within your code is as simple as BuildConfig.hostAPI.
Example:
Log.d(“Application”, “The host is “ + BuildConfig.hostAPI );
Output
For Release build is
The host is https://prod.somehost.com/rest/api
For Debug build is
The host is https://dev.somehost.com/rest/api
Quick note: the configuration name is case sensitive. If you specify hostAPI within your Gradle file, then use BuildConfig.hostAPI. If you specify Host, then of course it is BuildConfig.Host.
Flavors of Build Config
Let’s take this a step further. Say you have different Flavors of builds, flavorFoo and flavorBar. Here is how you could setup the different flavors to use specific hosts.
productFlavors {
flavorFoo {
buildConfigField ‘String’, ‘hostAPI’, ‘”http://somehost/foo”‘ dimension “foo”
}
flavorBar {
buildConfigField ‘String’, ‘hostAPI’, ‘”http://somehost/bar”‘ dimension “bar”
}
}
And of course, in your code you would reference the value by BuildConfig.hostAPI.
Example:
Log.d(“Application”, “The host is “ + BuildConfig.hostAPI + “ for flavor “ + BuildConfig.FLAVOR );
Output
For Flavor Foo
The host is http://somehost/foo for flavor foo
For Flavor Bar
The host is http://somehost/bar for flavor bar
Now you have multiple flavors of your product, wonderful. Let’s take this another step further, and you need to point your debug build of flavor ‘foo’ to a development host. Here is how, using the buildType.
productFlavors {
flavorFoo {
buildConfigField ‘String’, ‘hostAPI’, ‘”http://somehost/foo”‘ dimension “foo”
buildTypes {
debug {
buildConfigField ‘String’, ‘hostAPI’, ‘”http://somedevelopmenthost:3030″‘
}
}
}
flavorBar {
buildConfigField ‘String’, ‘hostAPI’, ‘”http://somehost/bar”‘ dimension “bar”
}
}
Example:
Log.d(“Application”, “The host is “ + BuildConfig.hostAPI + “ for flavor “ + BuildConfig.FLAVOR);
Output
For Flavor Foo Release
The host is http://somehost/foo for flavor foo
For Flavor Foo Debug
The host is http://somedevelopmenthost:3030 for flavor foo
For Flavor Bar
The host is http://somehost/bar for flavor bar
Conclusion
The main reason I lean toward placing API host references within my Gradle file is it gives me one place to reference the list of hosts used by my application. I do not have to look in multiple configurations files or look at the string resource of the development versus production flavors. One central place of reference. There are no complicated if statements to switch between debug or release builds, the build process sets what I need.
There is a downside to this approach, each time you change the values within the Gradle file, you have to sync your project with Gradle, which for larger projects, might take a few minutes. But you can always use those ‘sync’ times to get another cup of coffee.
Happy Coding.