Flavors in Android with Live Project usage Example

Anmol Sehgal
5 min readJul 2, 2018

In the last Android project we came across the use case where we needed to support 2 different maps for different users. For Chinese users we needed to load Baidu Maps and for non-Chinese users we needed to load the google maps. It was because google maps were not supported in China.

So based on the user location the particular Map was loaded.
So we integrated both the Map’s API’s and we were good to go.

Now to test whether which map was loaded and how it performed, we needed to hardcode the location, instead of taking it from GPS.
So to test Baidu, we hard coded the current country to “china” which then loaded Baidu maps, or else otherwise google maps.
It was working great, but at times it became tedious to keep hard coding the values and checking while releasing the build whether there was still any hard coding done. So to get away with such hard coding, FLAVORS were the best choice.

But lets first discuss about some key points related to flavors:

a. Build Types:

As the title says, using the build type, we can decide how to build our application. e.g. take the infamous example or debug and release build type. Whenever the module is created 2 build types are created automatically by the Android Studio. We can change the build type from the build variant but in this case debug is the default selected one.

Note: Both will have the entire code same, but the build types will only differ in their compilation configuration.

The build types are specified for all the different modules we have, in their gradle files(i.e. module level gradle).

android {
...
defaultConfig {
...
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}

debug {
minifyEnabled false
}
}

So here we specified 2 build types: release and debug with different configuration of minifyEnabled in them. It will be enabled in release mode and disabled in debug mode.

Note: minify is an Android tool that will decrease the size of your application when you go to build it. It’s extremely useful as it means smaller apk files! It detects any code or libraries that aren’t being used and ignores them from your final apk.

b. Product Flavors

This is what we used for our above use case. Product flavors are used when we we want our application to behave differently for different flavors.
So for our example, we used product flavors like we build 3 different flavors:

First flavor(GoogleMapFlavor): Here the Google maps were hard coded so that every time we build the app using this flavor we get Google maps functionality only.
Second flavor(BaiduMapFlavor): Here the Baidu maps were hard coded so that every time we build the app using this flavor we get Baidu maps functionality only.
Third flavor(LocationMapFlavor): Here there was no hard coding. But here the map to load was decided based on the user location.

So to debug our app accordingly, we build the certain flavour, without any need to go and hard code, and then remove the hard code after testing and so on. But the changes were required to be made once.
Finally at the time of release we released the LocationMapFlavor. So it involved 0% error to release the correct code base.

So in the module which had the map functionality, we specified the flavors like:

android {...
...
productFlavors {
baiduMapFlavor {
}
googleMapFlavor {
}
locationMapFlavor {
}
}

After the gradle file has been changed, now we need to change our code base according to our flavors.
So we need to hard code the location in Google/Baidu maps and get the GPS location in location flavor.

Add these 3 folders under the src as:

Now make the same java/xml file in the same structure in all these 3 flavor folders. And modify the code in these different files e.g.

e.g. if we have the MapLoader.java file in com.android.anmol.map.map package then make the same heirarchy in all the 3 flavors and modify the MapLoader.java there e.g.:

baiduMapFlavor:

package com.android.anmol.map.map;

public class MapLoader {

public static void loadMap() {
new BaiduMapLoader().load();
}
}

googleMapFlavor:

package com.android.anmol.map.map;

public class MapLoader {

public static void loadMap() {
new GoogleMapLoader().load();
}
}

locationMapFlavor:

package com.android.anmol.map.map;

public class MapLoader {

public static void loadMap() {
if (getCurrentLocation() == Location.BAIDU) {
new BaiduMapLoader().load();
} else {
new GoogleMapLoader().load();
}
}
}

And delete the MapLoader.java file from the src/main.

So we are all set.

Note that for this use case, the strategy design pattern is the perfect to use to load different Maps. But for simplicity we are loading the particular map by instantiating it directly. For strategy design pattern usage for this example please visit: https://goo.gl/uAVDvH

Now build the apk with the different build variant.

c. Build Variants:

Build variant is the combination of the build types and the product flavors.
e.g. in the example we have 2 build types:
1. Debug
2. Release

And 3 product flavors:
1. locationMapFlavor
2. baiduMapFlavor
3. googleMapFlavor

So combining them we will have 6 build variants like:
1. locationMapFlavorDebug
2. locationMapFlavorRelease
3. googleMapFlavorDebug
4. googleMapFlavorRelease
5. baiduMapFlavorDebug
6. baiduMapFlavorRelease

So select the particular build variant from the bottom right tab and select any build variant. Now the MapLoader.java will point to that flavor.

Now build the application. We will get the code base for that particular flavor only.

So using flavors we save our time from changing our code every time we needed to test or release the build for various locations. Instead we just build our application with correct flavor and we are done.

--

--