When Groovy becomes your Swiss army knife

Conditional Gradle Configuration by Build Variant

Optimize your build times and gain back precious minutes

radle is a powerful build tool that reigns as the dominant choice among Android developers. Despite its popularity, the complexity of fine-tuned optimizations can sometimes baffle newer engineers.

One circumstance had me and my team at UPMC Enterprises scratching our heads for weeks. We needed to conditionally include or exclude entire plugins and their associated configurations from our build based on the selected type or product flavor.

Establishing a Use Case from Experience

nyone who uses Gradle should know that most builds include at least one plugin. For Android, at least, it is common to see these plugins applied at the top of a configuration file:

This snippet should make any Android engineer feel right at home

In many cases, these plugins are necessary. However, my team and I encountered a plugin that triplicated our build times each time we included it in our project, regardless of its settings.

The culprit, we found, was a plugin called Dynatrace. The only way we knew we could alleviate ourselves from unnecessarily long development builds was to comment it out each time or wait an extra precious four minutes. No amount of hiding this plugin inside of buildTypes or productFlavors kept it from running.

We triplicated our build times with this additional configuration in our Gradle file

Thus, we established our need to include or exclude code in our Gradle file conditionally.

A Fundamental Misunderstanding

orcing a plugin and its relevant configuration to the confines of product flavor or build type may seem like the logical path forward. It certainly did to my team.

We failed to understand how Gradle operates. Before compiling any code, it evaluates each product flavor and build type as it calculates a task graph for subsequent execution during compilation. Therefore, even though we hid Dynatrace inside of only a few variants, it still ran and imported the plugin regardless of our selected build type.

Gradle Task Nomenclature

efore diving into our solution, it is essential to know how Gradle structures its variant-specific tasks. Consider this snippet:

This command intends to build an application in debug mode, and supposedly, without Dynatrace

One might run this simple command on CI machine without a second thought, but the naming convention makes it quite clear what the task is expected to do. It breaks down like this:

<task name> + (<product flavor> + <build type>) =
<task name> + <build variant>

In our project, we have several product flavors:

  • noDynatrace
  • dynatraceDev
  • dynatraceProd

… and several build types:

  • debug
  • staging
  • release

Therefore, I know that I can run the variant-specific task assemble with a noDynatrace flavor and in debug mode with assembleNoDynatraceDebug. The build console in Android Studio clearly shows this name.

The build variant window in Android Studio, highlighting the selected noDynatraceDebug variant
The build variant window in Android Studio, highlighting the selected noDynatraceDebug variant
The build variant becomes part of a variant-specific task name, as seen in Android Studio

This information supplied the final clue we needed to optimize our build time.

The Solution

he name of the task, which was assembleNoDynatraceDebug, in our case, is passed as a parameter to the Gradle script. Therefore, it is only necessary to verify the task name to make our important decision. Since Gradle configuration scripts are simply Groovy files at heart, this task became trivial.

Since we only pass a single task to our build tool, the solution was a simple as:

Dynatrace is properly excluded from the noDynatrace flavor

Conclusion

ur initial attempt to hide the offending code in a productFlavor or buildType block failed to improve our build times. We did not realize Gradle evaluated every block during the task graph calculation phase.

However, once we learned that the task name was available to us within the script, we were able to use some plain old Groovy to filter out the plugin and regain our precious four minutes.

I’m connecting people with technology, seamlessly. Since 2008, I’ve been a software architect and a leading engineer, delivering smart and intuitive software.

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