Hammer, pliers, nails
Hammer, pliers, nails (source: Pavlofox via Pixabay)

Problem

You want to customize the Gradle build process with your own tasks.

Solution

Add task elements to the Gradle build files. Use the extra properties supplied with the Android plug-in to make development easier.

Discussion

The Gradle DSL supports a task block for defining your own custom tasks. The API includes a wide range of existing tasks (like Copy, Wrapper, and Exec) that you can use simply by setting properties.

For example, the Copy task includes from and into properties, and the from block can be configured to exclude specified filename patterns. To copy all the APKs into a new folder, excluding those that are either unsigned or unaligned, add the task in Example 1 to the module build.

Example 1. Copy APKs to another folder
task copyApks(type: Copy) {
    from("$buildDir/outputs/apk") {
        exclude '**/*unsigned.apk', '**/*unaligned.apk'
    }
    into '../apks'
}

The buildDir property refers to the default build directory (app/build), and the dollar sign is used to inject it into a Groovy string (with double quotes). The documentation for the Copy task shows that the exclude block inside from supports an Ant-style directory name, meaning that ** matches all descendent directories.

If you don’t want to simply configure an existing Gradle task, you need to understand the distinction between the configuration and execution phases of Gradle. During the configuration phase, Gradle builds a DAG based on their dependencies. It then executes the desired task, along with its dependencies. All tasks are configured before any are executed.

Gradle prefers declarative tasks, like the Example 1 task, where you specify what you want done but not how to do it. If you need to execute commands, however, add a doLast block to your Gradle task.

The task shown in Example 2, from not available, is repeated here.

Anything done in the task either before or after the doLast block would be run during configuration time. The code in the doLast block itself runs at execution time.

The Android plug-in adds an android property, which in turn has an applicationVariants property that returns all the buildType/flavor combinations. In this case, they are all being printed to the console.

Note

The applicationVariants property is only available for the com.android.application plug-in. A libraryVariants property is available in Android libraries. A testVariants property is available in both.

To install all the debug flavors onto a single device (assuming they all have unique applicationId values), use the task in Example 3.

Example 3. Install all the debug flavors on a single device
task installDebugFlavors() {
    android.applicationVariants.all { v ->
        if (v.name.endsWith('Debug')) {
            String name = v.name.capitalize()
            dependsOn "install$name"
        }
    }
}

In this case, the dependsOn method shows that this is part of the configuration process rather than execution. Each variant name, like friendlyDebug, is capitalized (FriendlyDebug) and then the corresponding installation task (installFriendlyDebug) is added as a dependency to the installDebugFlavors task.

The result is during the configuration process, installArrogantDebug, installFriendlyDebug, and installObsequiousDebug are all added as dependencies to installDebugFlavors. Therefore, executing installDebugFlavors at the command line requires all three flavor installs.

Example 4. Installing all the debug flavors
./gradlew instDebFl
:app:preBuild UP-TO-DATE
:app:preArrogantDebugBuild UP-TO-DATE
:app:checkArrogantDebugManifest
// ... lots of tasks ...
:app:assembleArrogantDebug UP-TO-DATE
:app:installArrogantDebug
Installing APK 'app-arrogant-debug.apk' on 'Nexus_5_API_23(AVD) - 6.0'
Installed on 1 device.
:app:checkFriendlyDebugManifest
// ... lots of tasks ...
:app:assembleFriendlyDebug UP-TO-DATE
:app:installFriendlyDebug
Installing APK 'app-friendly-debug.apk' on 'Nexus_5_API_23(AVD) - 6.0'
Installed on 1 device.
:app:checkObsequiousDebugManifest
// ... lots of tasks ...
:app:assembleObsequiousDebug UP-TO-DATE
:app:installObsequiousDebug
Installing APK 'app-obsequious-debug.apk' on 'Nexus_5_API_23(AVD) - 6.0'
Installed on 1 device.
:app:installDebugFlavors

BUILD SUCCESSFUL

You can see that writing your own custom tasks requires at least some knowledge of Groovy. An extensive discussion is therefore a bit beyond the scope of this book, but there are several good Groovy resources available. Additional Groovy concepts are defined in this book as they occur.

See Also

The Gradle plug-in User Guide (see not available) shows available properties in the android object. The documentation for the Copy, Zip, or other Gradle tasks is found on the Gradle website. not available and not available have background information on the Groovy programming language and basic Gradle information, respectively.

Article image: Hammer, pliers, nails (source: Pavlofox via Pixabay).