Why Gradle?

At Google I/O 2013, Google introduced Android Studio, and with that, a push for developers to adopt Gradle. Gradle is a build tool similar to Maven and Ant with one important distinction: I actually understand it. Gradle utilizes build files written in Groovy, which syntactically is very similar to Java. Compared to Maven, our build files are about three times smaller on average, and it’s actually readable.

Admittedly, one of the reasons why Gradle seems so much better is that it has direct support from Google. Gradle utilizes plugins like all the other build tools, and Google has put in a lot of effort to make their plugin fully comprehensive, with a lot of added goodies that will make development easier. One of the things I like the most is that you can define your minimum and target SDK version, as well as your version code and name directly in the build file, and the Android Gradle plugin will inject these values into your AndroidManifest.xml for you. These values are directly related to your build, so it makes sense to define it at this layer.

When a Gradle build fails, the error output is generally very useful in diagnosing the problem, and will sometimes even offer a solution. No one likes fixing build errors, so at least you can move past it quickly. Your time should be spent developing; not appeasing the build tool gods. With great error diagnosis paired with a fast assembler (with parallel execution), you’ll spend a lot less time fiddling with build files.

 

Gradle Product Flavors

An application might have multiple configurations which slightly modify the code base, such as defining multiple endpoints for different servers. Achieving these small modifications might look something like this:

public static final String ENDPOINT = "http://production.website.com";
// public static final String ENDPOINT = "http://staging.website.com";

Making this modification is a small and simple task, but it is error-prone and slow, on top of it not being expandable if you needed to add additional changes to this configuration.

Product flavors allow you to group these configuration changes into their own code set and switch between them on the fly without code modification. Product flavors are achieved by defining them in the build.gradle file and creating the folder structure for each flavor.

build.gradle
build.gradle
android {
    ...
 
    productFlavors {
        integration
        staging
        production
    }
}

As you can see, each flavor has its own code set. A blue icon for the java folder signifies that flavor is active and is being included in the main code base. When another flavor is selected, the previous flavor becomes deactivated. To take advantage of this, each class that is defined in a flavor is duplicated by the other flavors with their configuration changes added in. For example:

staging/java/com/myapp/Constants.java
public static final String ENDPOINT = "http://staging.website.com";
integration/java/com/myapp/Constants.java
public static final String ENDPOINT = "http://integration.website.com";
production/java/com/myapp/Constants.java
public static final String ENDPOINT = "http://production.website.com";

Since the package and class names are the same, including the Constants class in your networking class will always resolve.

You switch between product flavors using the Build Variants toolbar located at View > Tool Windows > Build Variants. Every application has two build types (debug and release), so the build variants list will show every combination of build type and product flavor.

Each flavor has its own task that can be invoked. To assemble the integration product flavor with the debug build type: gradle assembleIntegrationDebug. Invoking a task that does not define a product flavor will run that task for each product flavor. For instance, running gradle assembleDebug will run the assemble task with the debug build type for integration, staging, and release.

 

Common/Unflavored Code

The majority of your code is likely not part of a flavor. This code continues to reside in src/main/java and is part of EVERY flavor.

Therefore, code can only go either in src/main/java or in one of the flavors’ folders but not both.

Putting code in both places will result in “duplicate class” errors from the compiler.

Gradle can be slow at times, but there are ways to speed this process up. Android integration with Gradle is still in its infancy, so hopefully with future update, it’ll continue to get faster.

 

How to Speed up Gradle

    1. In Finder, navigate to ~/.gradle
    2. Open gradle.properties. If it does not exist, create it.
    3. Add the following lines:
      gradle.properties
      org.gradle.daemon=true
      org.gradle.parallel=true
    4. Save and close the file.
    5. Restart Android Studio if necessary.

 

Additional Reading

Gradle Plugin User Guide – Build Variants