Learn to use the most powerful Gradle system in Android effectively

Android Product Flavors

Here is everything you need to know about product flavors and real-time problems with solutions

Photo by wu yi on Unsplash

This is going to take time, grab a cup of coffee and make yourself comfortable

  1. Overview
  2. When to use Product Flavors
  3. Basics
  4. Flavors-creation
  5. Resource and java Files management for different flavors
  6. 3rd Party library integrations for different flavors
  7. Project Config at Product flavors level
  8. How to switch between build variants
  9. Real-time problems & solutions
  10. Useful links

Overview

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.

Situation 1

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.

Situation 2

Have you ever seen Free and Pro versions of the same app in playstore, Pro version have all features of the free version, also with pro features.

This will be an ideal situation to use Product Flavors.

Basics

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

build variants

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.

Flavors Creation

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

build types and product flavors in gradle

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.

Resource Files

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

  1. Target Source set is nothing but the source code directories for selected flavor.
  2. 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.

Java Files

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

  1. Res and Java directories under PaidDebug
  2. Res and Java directories under PaidRelease
  3. 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

PaidDebug\Res\Drawable\

PaidRelease\Res\Drawable\

Main\Res\Drawable\

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

PaidImplementation ('com.squareup.picasso:picasso:2.71828')

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

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.

Minor Changes

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 🤵 ).

Bonus

To learn more about Build Variants, Gradle, Kotlin DSL & Android advanced development read the following articles:

Useful links

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

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.

You can find me on Medium, Twitter and LinkedIn Cheers!

Thank you for reading.

Learn. Code. Write. Repeat. Visit me at https://about.me/sivaganesh_kantamani & Join my email list at https://sgkantamani.substack.com/p/subscribe

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store