This is going to take time, grab a cup of coffee and make yourself comfortable
- When to use Product Flavors
- Resource and java Files management for different flavors
- 3rd Party library integrations for different flavors
- Project Config at Product flavors level
- How to switch between build variants
- Real-time problems & solutions
- Useful links
Product flavors are nothing but preparing different dishes using the same core ingredients but adding minor flavor toppings to get a different taste. To better understand product flavors let us consider a generic example
Let’s take the preparation of an omelet
Base Ingredients: 2 eggs, salt, pepper, butter, cheddar, chopped chives
With the above ingredients you can make a perfect omelet. Now you wanna have a Potato Chip Omelet, it’s simple we need to add below flavor ingredients to above base ingredients.
Flavor Ingredients: 3 c. potato chips, Arugula salad
The same process works with different flavors of the omelet.
The core principle of Product flavors in android is same as preparing different flavors of omelet.
Here base ingredients are your common code in the main directory which is available to all flavors
Also, you will have different code directories for each flavor to create flavor specific code like flavor ingredients.
When to use Product Flavors
Now we know what are Product flavors in Android next we need to know when to use them.
There are many situations where we use product flavors, I would like to explain my experience and one of the most common situations where many developers opt-in for this feature.
A few months back in one of the companies I’m working as a lead Android developer had a contract with another leading company now they want to release the existing app with minor changes(logos, colors, minor additional features) as a new app in PlayStore. The core functionality of the app remains the same but there will be some decoration-al changes to the app.
This is one of the best situations where you can use Product Flavors.
This will be an ideal situation to use Product Flavors.
Android by default uses two build types debug & release. When you run an app through android studio it will install debug apk and while building apk you can see both build types.
Build types are different from product flavors. Product flavors are the top-level distribution of app variants and build types are internal variants of each flavor. Have a look
In the above picture, we have 6 variants of apks that we can generate. Free and Paid are flavors whereas debug, stagging and release are build types. It is pretty much clear that each flavor has all build types.
Google made it pretty much easy to create product flavors in android, we just need to add productFlavors block inside android block in app-level build.gradle file.
Its that simple to create product flavors. Now let’s get into some complicated situation where you want development, stagging and production build types for each flavor. Let’s see how we can do that
Resource and java Files management for different flavors
At this point, we know how to create different flavors with buildTypes but it isn’t enough in real-world we should be able to create resource and java files specific to each variant.
Before that you should know about sourceSets block in gradle, it defines which directories of code will be available in specified build types. You’ll understand this as read on.
First, let’s see how to create resource files for each flavor
Switch to project view in the left panel and then expand all directories until src and then right-click on src then navigate to
new > Folder > Res Folder
Then you’ll see a popup with two fields
- Target Source set is nothing but the source code directories for selected flavor.
- The New folder location is the location where the file will be created.
Similarly, we can create a directory for all flavored build types if necessary.
Observe that at the end of the above demo, a new line is added in build.gradle file with sourcesets block like below
Make sure that there are no spaces in the line, for some reason, it was not importing into the gradle file in correct formate.
Creating a java directory for each flavor is similar to resource directories creation, the only difference is that we select a java folder instead of the res folder. Have a look
Now that you observe source set block for PaidRelease has included java src directories. have a look
Source set describes which code directories should be included while building apk for a particular build type.
Here directories in the main block will be included in all flavors as a common code.
PaidRelease build type will include both main block directories and also directories within PaidRelease block.
res.srcDirs: Include resource directories
java.srcDirs: Include java file directories
We can also assign PaidRelease directories to debug and stagging variants, have a look
It’s not over yet, you can also assign multiple resource and java directories to a build type.
As you see clearly, PaidDebug variant contains three sourcesets namely
- Res and Java directories under PaidDebug
- Res and Java directories under PaidRelease
- Res and Java directories under Main
Let me simplify even more, for suppose we want to display a launcher icon then normally we call R.drawable.ic_launcher, When we initiate this request system first try to get drawable from PaidDebug directory if not found it’ll try to pick from PaidRelease directory and if still not found it’ll get from the Main directory. So the order of picking any src file will be as follows for PaidDebug Build variant
3rd Party library integrations for different flavors
The paid version has some extra features which require an additional library for paid flavor variants, so we should only include this library for paid variants. Library integrations can be done specifically to particular flavor variants, have a look
Combine the flavor name with implementation tag and import the library. Those library features will only available to specific flavors.
Project Config at Product flavors level
MinSdk version, TargetSdk version, versionName, versionCode, package name and more project-level config can be maintainable in each flavor if required. Have a look
How to switch between build variants
If you use android studio at least 2months — 4months you would know that you can access anything in the studio by pressing the shift button twice and search.(press shift twice and search build variants that’s it)
I’ve used this way for almost 2months believe me, when I say this, it’s not the way you wish to go because working with product flavors means shifting between build variants is one of the common things you do. Take the leverage of creating dynamic(developer level ) shortcuts in android studio.
Refer below article for adding custom shortcuts in android studio
Keyboard shortcuts | Android Developers
Android Studio includes keyboard shortcuts for many common actions. Table 1 shows the default keyboard shortcuts by…
Real-time problems & solutions
How do flavors work while building an APK
This is the most interesting part for me because this is where most of the magic is done while building an apk you should select a build variant based on that android build system to decide which source-sets to be included in the apk.
For suppose you’re building a PaidRelease apk then it is bundled with Java & Res directories of main and also including whatever source-sets we mentioned for this build variant in gradle file.
This means the generated apk only have whatever classes & resources that are required and leaving rest of the flavor directories which results in perfect APK size.
This works the same with App bundles.
Package Structure in different Flavors
We have common code in the main directory which is available to all flavors so we can call any activity in the main directory from any activity in any flavor, but what if you want to call an activity which is present in flavors(with different functionality in-it) from activity in the main directory.
To solve this problem we need to maintain the same package structure for all flavors as shown below
In this way when you call an activity (here ActivityPlanDetails) android system will take care of invoking the activity from your current working flavor.
Same with the manifest file, mention an activity as shown below you will be fine in working both paid and free flavors. Android build system will take care of registering the activity from the selected flavor.
You might encounter a situation where there is only a minor change in the entire screen now you have to maintain the same class in all flavors.
In my experience when I encountered a situation like this, I have maintained a flag in BuildConfig file to know which variant is running and implement functionality according to it. I would do this for only very minor changes.
This is just a hack, don’t maintain huge code differences based on this flag and maintain the flag only in BuildConfig file.
In my journey with product flavors, I’ve used this flag only to show & hide a button in a fragment with huge code.
Sometimes you need to bend rules to get justice.(Harvey Specter 🤵 ).
To learn more about Build Variants, Gradle, Kotlin DSL & Android advanced development read the following articles:
Configure build variants | Android Developers
This page builds on the Configure your build overview to show you how you can configure build variants to create…
Below link is about gradle, but going through it will help you figure out how to solve problems like File providers for different product flavors
Gradle tips and recipes | Android Developers
Gradle and the Android plugin for Gradle provide a flexible way to compile, build, and package your Android app or…
I found only this two are useful, rest are bits & pieces, that’s the main reason I’m writing this article. If I miss anything please let me know in comments, I’m happy to write the second part of this article.
As of my experience with product flavors, if the project is enterprise-level don’t prefer maintaining more than three flavors. It would be hard to maintain the code, as simple as it seems to be in the beginning, it will be harder and harder as you go on.
Thank you for reading.