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.
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. 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: After running the debug build on our device, we went to Settings | Applications | Our App Name. Following is the screenshot of the app info: The version number at the bottom has changed. This is useful to differentiate between different builds.
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”] 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 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 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.
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.
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: 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: 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. WOW! Different colored FloatingActionButton and application names. Try clicking on the FAB and you’ll see a flavor specific SnackBar text.
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: Now we can use the appLabel
key in the AndroidManifest.xml file as: This brings an end to this tutorial. You can download the project from the link below:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
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.
error : Gradle DSL method not found: ‘applicationId()’
- Ravi Vaniya
Well explained
- Jagadisha
very well explained within few words. Excellent
- Rabiun Islam
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