Create an app with multiple product flavors

Build variants

Nikitha Gullapalli
7 min readNov 24, 2020

Topics covered: build types, build flavors- paid and free, flavor dimensions, filter variants, Create source sets and reusing code, merging resources from source sets, Per-variant dependency Configuration, Adding AdMob to free version and making paid version add free.

Profiles:
LinkedIn: https://www.linkedin.com/in/nikitha-gullapalli/
GitHub: https://github.com/nikitha2/Examples_Gradle_BuildVariants.git

It is always convenient to have different versions of your app. free and paid versions is a common example. We also want debug to test the app and release versions of the app when it is ready for play store. Instead of constantly maintain different versions of the app, we can write the code unique to each variant and gradle will take care of the rest.

A build variant is a cross product of a build type and product flavor. So lets look at how to had different build variants and how to make free version different from the paid version.

Build Variants with 4 variants

Build type-build type is transparent to the user and only useful to the developer. Used to control how the app is built and packaged. By default every app has release and debug types. Debug is used during development and release is used to deploy in the app store.

Build Flavors- build flavors control features that are visible to end users. The most common example are paid and free versions of an app.

Steps to add Build type:

  1. In module gradle.build add the new build type in build type block.
Add the new build type in build type block

2. sync the build and check if the new build type is added to the list.

Click on build variants tap on the left and check that the new build type is added to the dropdown as shown

Build flavors

a. Steps to add Build flavors

1.In module gradle.build add the new build flavors in build flavors block.

Add the new build flavors in build flavors block.

2. sync the build and after the sync completes, Gradle automatically creates build variants based on your build types and product flavors, and names them according to <product-flavor><Build-Type>.You can select the required build variant from Build > Select Build Variant from the menu bar or as shown below

Click on build variants tap on the left and check that the new <product-flavor><Build-Type> are added to the dropdown as shown

b. Combine multiple product flavors with flavor dimensions

Combine multiple product flavors with flavor dimensions- In some cases we might want to create different configurations for the “full” and “demo” product flavors that are based on API level. To do this, the Android plugin for Gradle allows you to create multiple groups of product flavors as flavor dimensions. When building your app, Gradle combines a product flavor configuration from each flavor dimension you define, along with a build type configuration, to create the final build variant. Gradle does not combine product flavors that belong to the same flavor dimension.

‘Api’ has higher priority than ‘mode ’ dimension as it is first in the list

build variant is creates with format: Build variant: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]

eg: minApi24DemoDebug

Filter variants

Gradle creates a build variant for every possible combination of the product flavors and build types that you configure. However, there may be certain build variants that either you do not need or do not make sense in the context of your project. You can remove certain build variant configurations by creating a variant filter in your module-level build.gradle file.

This code ignores build variant that has build flavor- minApi21 and build type- Demo

Create source sets

By default, Android Studio creates the main/ source set and directories for everything you want to share between all your build variants. However, you can create new source sets to control exactly what files Gradle compiles and packages for specific build types, product flavors (and combinations of product flavors when using flavor dimensions), and build variants. For example, you can define basic functionality in the main/ source set and use product flavor source sets to change the branding of your app for different clients, or include special permissions and logging functionality only for build variants that use the debug build type.

When you create a new build variant, Android Studio doesn’t create the source set directories for you, but it does give you a few options to help you. For example, to create just the java/ directory for your "debug" build type:

  1. Open the Project pane and select the Project view from the drop-down menu at the top of the pane.
  2. Navigate to <Project name>/app/src/.
  3. Right-click the src directory and select New > Folder > Java Folder.
  4. From the drop-down menu next to Target Source Set, select debug.
  5. Click Finish.

To create a resource file

  1. Navigate to <Project name>/app/
  2. Right-click the app directory and select New > Android resource file
  3. Pop-up like below appears. Select what source set we want the resource file to be in and click ok (eg: select free). It will appear under src>free>res>values

4. click gradle on the right side of the screen. Navigate to <Project name>/tasks/install.. Double click on instalFreeDebug.

Recourses merging

Android gradle plugin creates build variant src folders as shown below. Depending on our app need we can add our files in respective folders. For example: if I need a file for all variants of release then I can add it in release. if I need it only for paidRelease version- then i can add it in paidRelease folder.

build variant folders

We can understand this process better by looking at the below diagram. For example if we want to compile code for paidDebug version. The complier first merges main files. then rewrites overwritten files in debug folder. Then if there are any files in paidDebug rewrites those files and compiles the code. Basically less specific configurations are overwritten by more specific configurations.

steps t

For resources like string , values, etc. files are merged and overwritten based on id.

Per-variant dependency Configuration

In additional to having unique source directories for each source set, we can
also assign them unique dependencies. Essentially, this means we can declare dependencies independently for each product flavor.

Let’s continue to use the free vs paid app flavor example, since it’s a
pretty common one. It’s is probably likely that we would enable ads in our
free version, but not in the paid version of the app. Utilizing Google’s ad
services requires us to depend on the ad services library. However, we don’t
want to unnecessarily bloat the paid version of our app by including a
library that won’t be used. To solve this problem, we can simply declare this
dependency only for the ‘free’ flavor. We can do this because, since flavors
are just extra source sets, Gradle has created flavor-specific configurations
that we can assign our dependencies too. I think you can guess what these
configurations are prefixed with.

freeImplementation 'com.google.android.gms:play-services-ads:19.5.0'   // will apply only to the free version

Configuration Generated Tasks

If i want to configure task to change name of the debug buildvariants below is the code.

applicationVariants.all{
if(buildType.name=='debug'){
javaComplie.options.compilerArgs=['-verbose']
}
}

Adding AdMob to free version and making paid version add free.

Follow the steps here to add ads to your app.

  1. Add dependency in build.gradle file- freeImplementation will make this library available only to the files under free source sets folder. free/src/java.
freeImplementation 'com.google.android.gms:play-services-ads:19.5.0'

2. Update your AndroidManifest.xml and create view to hold the ads

An app ID is a unique ID number assigned to your apps when they’re added to AdMob. The app ID is used to identify your apps. To find app ID: follow the steps here.

An ad unit ID is a unique ID number assigned to each of your ad units when they’re created in AdMob. The ad unit ID is added to your app’s code and used to identify ad requests from the ad unit.

To find app ID: follow the steps here.

Conclusion:

I know we covered wide range of topics in this article. So understand better understanding I encourage you to read the official documentation. You can find documentation here.

References:

Udacity: https://classroom.udacity.com/nanodegrees/nd801/parts/5a4a1676-de82-4954-9fb9-ebe492ba6142/modules/890dda0e-bc34-4a3a-86f1-06063710b3b9/lessons/4020658782/concepts/43306600370923

https://developer.android.com/studio/build/build-variants#product-flavors

--

--