Advanced Android Flavors Part 5 — The BuildConfig Strikes Back

This is the fifth article in my ‘Advanced Android Flavors’ series.
The first one is here.
The second one is here.
The third one is here.
The fourth one is here.
We all have configurations in our code. If you’re an organized individual, you might be using the resource system or have a config file. My configuration usually consists of a bunch of constants in various locations in my code. What happens when we want these constants to be flavor-specific? 🤔
The XML / config file users get flavor support for free. Simply put your file or resource inside the flavor named folder and you’re done. For the rest of us, it’s time to use the BuildConfig.
The BuildConfig
So what is this BuildConfig? It’s an auto-generated class that contains (wait for it) config constants that are specific to a build. This class is generated for each of our build variants separately. Out of the box, it contains a bunch of information about our build, such as:
- The DEBUG flag.
- Our application ID.
- Each flavor dimension and the combined flavor.
- The version name and version code.
The cool thing is that we can add our own custom flavor specific fields to the BuildConfig. This is done with the buildConfigField command. It looks like this:
buildConfigField 'long', 'FLAVOR_LONG', '11500L'
buildConfigField 'String', 'FLAVOR_STRING', '"Blah blah"'
Let’s break it down:
- The first parameter is the type of this constant.
- The second parameter is the constant name
- The third parameter is the constant value. Notice I have to include the double quotes when it comes to strings.
You can add this to each of your product flavors, to your build types (debug / release), or inside the config section of the build.gradle file. But since we have quite a few dimensions that create many combinations, I find it easiest to set build config fields per build variant.
Variant Specific Fields
To to that we need to add a section to our build.gradle file, at the very bottom of the android section:
applicationVariants.all { variant ->}
This addition allows us to loop over all of our build variants and perform variant specific actions. We’ll use it to insert constants into the BuildConfig. It could look something like this:
applicationVariants.all { variant ->
def name = variant.getName() // Default values
variant.buildConfigField 'boolean', 'ENABLE_ANALYTICS', 'false' // Specific values
if (name.contains("Dev")) {
variant.buildConfigField 'String', 'SUBDOMAIN', '"dev"'
} else if (name.contains("Staging")) {
variant.buildConfigField 'String', 'SUBDOMAIN', '"staging-api"'
} else if (name.contains("Production")) {
variant.buildConfigField 'String', 'SUBDOMAIN', '"api"'
variant.buildConfigField 'boolean', 'ENABLE_ANALYTICS', 'true'
}
}
By looping over each of our variants, we have the flexibility to set up our config fields any way we want them. We can also easily set repeating default values. In this example we did the following:
- We set the the ENABLE_ANALYTICS flag to default to false. for non-productions variants.
- We set the subdomain of our server according to the server flavor dimension.
The way we would use the subdomain in our code is super simple:
import static com.mycompany.BuildConfig.SUBDOMAIN;public class Api { private static final SERVER_URL =
String.format("https://%s.mycompany.com", SUBDOMAIN);}
That’s just a simple example. You can use the BuildConfig to create complex flavor specific configurations and take those constants out of your code.
Goodbye Flavors (for now…)
This will (probably) be the last entry in this series. There’s always more that can be said, but I feel that I have covered the essentials. Good luck on your flavor adventures! 😊