Tutorial

Android Build Types and Product Flavors

Published on August 3, 2022
author

Anupam Chugh

Android Build Types and Product Flavors

In this tutorial, we’ll be discussing Android Build Types and Product Flavors. We’ll see how they make our Android Development easier and faster especially when we’re creating applications with minimal differences. These differences can be as small as changes in themes and app icons or can be for different stages of the product such as dev, beta, production etc. Create a new project in your Android Studio and choose the Basic activity. In the next section, we’ll look at build types.

Android Build Types

Once the new project is created, by default it consists of two build types/variants - debug, release. Debug is the build type that is used when we run the application from the IDE directly onto a device. A release is the build type that requires you to sign the APK. The release builds are meant to be uploaded to the play store. In the release build type, we obfuscate the code using ProGuard to prevent reverse engineering. Following image shows the default build types. android build types variants In the build.gradle by default, only the release build type block is written:

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

We can add properties on the other build types too. Before we do that let’s add some signingConfigs to the android block.

signingConfigs {
        release {
            storeFile file("release-key.keystore")
            storePassword 'password'
            keyAlias 'alias'
            keyPassword 'journaldev'
        }
    }

Make sure you’ve created a signed key file with the release-key name and the above password from Build | Generate Signed APK for the above code to work.

Let’s add new build types and more properties to the buildConfig.

buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug{
            applicationIdSuffix ".debug"
            versionNameSuffix "-debug"
        }

        beta{
            signingConfig signingConfigs.release
            applicationIdSuffix ".beta"
            versionNameSuffix "-beta"
        }
    }

applicationId suffix appends the string to the applicationId of the application. versionName does the same on the version name present in the defaultConfig. Now we have 3 build variants: android build type variants After running the debug build on our device, we went to Settings | Applications | Our App Name. Following is the screenshot of the app info: android build types debug screenshot app info The version number at the bottom has changed. This is useful to differentiate between different builds.

BuildConfig

The BuildConfig.java class is auto-generated when different buildFlavors are created. We can set Build Config Fields in our build.gradle.

buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug{
            applicationIdSuffix ".debug"
            versionNameSuffix "-debug"
            buildConfigField "String", "TYPE", '"I AM A DEBUG NINJA"'
        }

        beta{
            signingConfig signingConfigs.release
            applicationIdSuffix ".beta"
            versionNameSuffix "-beta"
            buildConfigField "String", "TYPE", '"I AM A BETA NINJA"'
        }
    }

[caption id=“attachment_21554” align=“aligncenter” width=“500”]android build config auto generated BuildConfig for the beta build[/caption] The BuildConfig.java class and its fields can be accessed by our Activities directly. We can also add resources fields using in the buildConfigs. Add the following in your beta buildConfig and it’ll be auto-created in the resources | strings.xml folder. resValue "string", "my_name", "Anupam Beta"

Android Product Flavors

Android Product Flavors are used to create different app versions. App versions can be free or paid. They can have different themes and texts. They can use different environments or APIs. Let’s assign two product flavors free and paid in our application.

productFlavors{

        free{
            applicationId "com.journaldev.androidproductflavors.free"
        }

        paid{
            applicationId "com.journaldev.androidproductflavors.paid"
        }
    }

For the above code in the build.gradle to successfully create the flavors we need to set flavor dimensions. Flavor Dimensions is a way to group flavors by a name. For now, we’re using just a single group. Add the following line in your defaultConfig block:

flavorDimensions "default"

Now syncing the gradle would give you the following product flavors: android product flavors variants

Android Build Variants combine build types and product flavors. They create a matrix of all combinations.

Now in our project, the main folder consists of the common logic across all app versions. To write flavor specific code, create the folder with the same name as the flavor.

  • The java classes with the same name in the flavor folders won’t override the main folder.
  • The res folder in the main should only have those directories that are common to all flavors.

Now let’s create the free and paid folders in our project and create separate res folders for each.

Project Structure

android-product-flavors-project-structure So in the free and paid folders, we’ve created res folders in which the app icons and strings.xml are different for each flavor. Our final build.gradle file looks like this: android product flavors build gradle content_main.xml class is given below:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/textViewLabel"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

In the textView, we set the string from the strings.xml. The strings.xml resources for each of the flavors contains the same key:

<string name="textViewLabel">Hello free</string> - For free
<string name="textViewLabel">Hello Paid</string> - For paid.

MainActivity.java:

package com.journaldev.androidproductflavors;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Flavour: "+BuildConfig.FLAVOR + " My type: "+BuildConfig.TYPE , Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

We’ve run two flavors: freeDebug and paidDebug on our device. Here’s the look of them: android product flavours app output WOW! The left app is the free one and right one is the paid one. Let’s launch each of them. Following are the screenshots from them, side by side. android product flavors WOW! Different colored FloatingActionButton and application names. Try clicking on the FAB and you’ll see a flavor specific SnackBar text.

Manifest Placeholders

You can set the app name for each product flavor directly in the AndroidManifest.xml file without the need to create separate strings.xml files, using Manifest Placeholders in your build.gradle. Following is the way they are defined: android product flavors manifest placeholders Now we can use the appLabel key in the AndroidManifest.xml file as: android product flavors manifest This brings an end to this tutorial. You can download the project from the link below:

AndroidProductFlavors

Download From GitHub Repository

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Anupam Chugh

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
October 14, 2020

error : Gradle DSL method not found: ‘applicationId()’

- Ravi Vaniya

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    January 24, 2020

    Well explained

    - Jagadisha

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      November 5, 2019

      very well explained within few words. Excellent

      - Rabiun Islam

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        May 30, 2019

        Great tutorial, very informative. Though I was also expecting that you show about the project structure for implementing flavour specific java classes or activities .

        - Siddharth Karnik

          Try DigitalOcean for free

          Click below to sign up and get $200 of credit to try our products over 60 days!

          Sign up

          Join the Tech Talk
          Success! Thank you! Please check your email for further details.

          Please complete your information!

          Become a contributor for community

          Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

          DigitalOcean Documentation

          Full documentation for every DigitalOcean product.

          Resources for startups and SMBs

          The Wave has everything you need to know about building a business, from raising funding to marketing your product.

          Get our newsletter

          Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

          New accounts only. By submitting your email you agree to our Privacy Policy

          The developer cloud

          Scale up as you grow — whether you're running one virtual machine or ten thousand.

          Get started for free

          Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

          *This promotional offer applies to new accounts only.