aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • Programming

Gradle And AGP Build APIs: How To Write A Plugin

  • aster.cloud
  • November 30, 2021
  • 5 minute read

This is the second article in this MAD skills series. In the previous article you’ve seen the basics of Gradle and how to configure the Android Gradle Plugin. In this article you’ll learn how to extend your build by writing your own plugin. If you prefer to watch this content instead of reading, check out the video below:

Starting with version 7.0, Android Gradle Plugin now offers stable extension points for manipulating variant configuration and the produced build artifacts. Some parts of the API were finalized only recently, so I’m going to use the 7.1 version (in Beta at the time of writing) of AGP throughout this article.


Partner with aster.cloud
for your next big idea.
Let us know here.



From our partners:

CITI.IO :: Business. Institutions. Society. Global Political Economy.
CYBERPOGO.COM :: For the Arts, Sciences, and Technology.
DADAHACKS.COM :: Parenting For The Rest Of Us.
ZEDISTA.COM :: Entertainment. Sports. Culture. Escape.
TAKUMAKU.COM :: For The Hearth And Home.
ASTER.CLOUD :: From The Cloud And Beyond.
LIWAIWAI.COM :: Intelligence, Inside and Outside.
GLOBALCLOUDPLATFORMS.COM :: For The World's Computing Needs.
FIREGULAMAN.COM :: For The Fire In The Belly Of The Coder.
ASTERCASTER.COM :: Supra Astra. Beyond The Stars.
BARTDAY.COM :: Prosperity For Everyone.

Gradle Tasks

I’ll start with a new clean project. If you want to follow along, you can create a new project by selecting the basic activity template.

Let’s start with creating a task and printing out, guess what, hello world. To do this, in the app level build.gradle.kts file, I’ll register a new task and name this task ‘hello’.

tasks.register(“hello”){ }

Ok, now that the task is ready let’s print out hello and also add the project name. Notice this build.gradle.kts file belongs to the app module, so project.name will return this module’s name which is ‘app’. Instead I’ll use project.parent?.name, which returns the name of the project.

tasks.register("hello"){
    println("Hello " + project.parent?.name)
}

Now it is time to run the task. Looking at the task list, I can see that my new task is listed here.

The new task is listed in Gradle pane in Android Studio

I can double click the hello task or execute this task through terminal and see the hello message printed in the build output.

The task prints hello message in the build output

When I check the logs, I can see that this message is printed during the configuration phase. Configuration phase is really not about executing the task function, like printing Hello World in this example. Configuration phase is a time to configure a task to influence its execution. You can tell the task about the inputs, parameters and where to put the output.

Read More  A New Look For The Red Pin On Maps JavaScript, Android And iOS

Configuration phase runs regardless of which task is requested to run. Running time consuming code in the configuration phase can result in long configuration times.

The task execution should only happen during the execution phase so we need to move this print call to the execution phase. To do that I can add doFirst() or doLast() which will print the hello message at the beginning or at the end of the execution phase respectively.

tasks.register("hello"){
    doLast {
        println("Hello " + project.parent?.name)
    }
}

When I run the task again, this time I can see that the hello message is printed during the execution phase.

The task now prints the hello message in execution phase

Right now my custom task is located in the build.gradle.kts file. Adding custom tasks to the build.gradle file is a simple way to create custom build scripts. However, as my plugin code gets more complicated, this doesn’t scale well. We recommend placing the custom task and plugin implementations in a buildSrc folder.

Implementing the plugin in buildSrc

Before writing any more code, let’s move my hello task to buildSrc. I’ll create a new folder and name it buildSrc. Next I create a build.gradle.kts file for the plugin project so Gradle automatically adds this folder to build.

This is a top level directory in the root project folder. Notice I don’t need to add this as a module in my project. Gradle automatically compiles the code in this directory and puts it in the classpath of your build script.

Next I create a new src folder and a new class named HelloTask. I convert this new class to an abstract class and extend DefaultTask. Next, I’ll add a new function called taskAction, annotate this function with @TaskAction annotation and move my custom task code from build.gradle.kts to this function.

abstract class HelloTask: DefaultTask() {    
    @TaskAction
    fun taskAction() {
        println("Hello \"${project.parent?.name}\" from task!")
    }
}

Now that my task is ready I’ll create a new plugin class which needs to implement Plugin and override the apply() function. Gradle will call this function and pass in the Project object. To register the HelloTask, I’ll call register() on project.tasks and give this new task a name.

class CustomPlugin: Plugin<Project> {
    override fun apply(project: Project) {
        project.tasks.register<HelloTask>("hello")
    }
}

At this point I can also declare that my task depends on another task.

class CustomPlugin: Plugin<Project> {
    override fun apply(project: Project) {
        project.tasks.register<HelloTask>("hello"){
            dependsOn("build")
        }
    }
}

Next, let’s apply the new plugin. Note that, if my project had more than one module, I could reuse this plugin by adding it to other build.gradle files as well.

plugins {
    id ("com.android.application")
    id ("org.jetbrains.kotlin.android")
}apply<CustomPlugin>()android {
   ...
}

Now I’ll execute the hello task and observe that my plugin works just like before.

Read More  Google I/O 2019 | Kotlin Under the Hood: Understand the Internals

./gradlew hello

Now that I moved my task to buildSrc, let’s take it a step further and discover the new Android Gradle Plugin APIs. AGP offers extension points on it’s lifecycle while building the artifacts.

To start with the Variant API let’s first discuss what a Variant is. Variants are different versions of your app that you can build. Let’s say besides a fully functioning app, you also want to build a demo version of your app or an internal version for debugging purposes. You can also target different API levels or device types. V​​ariants are created by combining build types, such as debug and release, and product flavors that are defined in the build script.

Using the declarative DSL in your build file to add a build type is perfectly fine. However, doing that in code gives your plugin a way to influence the build in ways that are not possible or difficult to express using declarative syntax.

AGP starts the build by parsing the build script, and the properties set in the android block. The new Variant API callbacks allow me to add a finalizeDSL() callback from the androidComponents extension. In this callback I can change the DSL objects before they are used in Variant creation. I’ll create a new build type and set its properties.

val extension = project.extensions.getByName(
    "androidComponents"
) as ApplicationAndroidComponentsExtension
       
extension.finalizeDsl { ext->
    ext.buildTypes.create("staging").let { buildType ->
        buildType.initWith(ext.buildTypes.getByName("debug"))
        buildType.manifestPlaceholders["hostName"] = "example.com"
        buildType.applicationIdSuffix = ".debugStaging"
    }
}

Notice in this phase, I can create or register new build types and set their properties. At the end of this phase, AGP will lock the DSL objects, so they cannot be changed. If I run the build again, I can see that a staging version of the app is built.

Read More  Google Cloud Next 2019 | Building Game AI for Better User Experiences

Now, let’s say one of my tests is failing and I want to disable unit tests to build an internal version to figure out what is wrong.

To disable unit tests, I can use the beforeVariants() callback which allows me to make such changes through the VariantBuilder object. Here I’ll check if the current variant is the one I created for staging. Next, I’ll disable the unit tests and set a different minSdk version.

extension.beforeVariants { variantBuilder ->
    if (variantBuilder.name == "staging") {
        variantBuilder.enableUnitTest = false
        variantBuilder.minSdk = 23
    }
}

After this phase, the list of components and artifacts that will be created are now finalized!

You can find full code listing for this sample below. Also if you want to see more samples like this, make sure to check out the gradle-recipes repo on Github.

Summary

Writing your own plugins, lets you extend Android Gradle Plugin and customize your build to your project’s needs!

In this article you’ve seen how to use the new Variant API to register callbacks in AndroidComponentsExtension, use DSL objects to initialize Variants, influence which Variants are created, and their properties in beforeVariants().

In the next article, we will take this even further by introducing the Artifacts API, and showing you how to read and transform artifacts from your custom Tasks!

By Murat Yener
Source Medium


For enquiries, product placements, sponsorships, and collaborations, connect with us at [email protected]. We'd love to hear from you!

Our humans need coffee too! Your support is highly appreciated, thank you!

aster.cloud

Related Topics
  • AGP
  • Android
  • Android Studio
  • Gradle
  • Medium
  • Variant
You May Also Like
View Post
  • Architecture
  • Data
  • Engineering
  • People
  • Programming
  • Software Engineering
  • Technology
  • Work & Jobs

Predictions: Top 25 Careers Likely In High Demand In The Future

  • June 6, 2023
View Post
  • Programming
  • Software Engineering
  • Technology

Build a Python App to Alert You When Asteroids Are Close to Earth

  • May 22, 2023
View Post
  • Programming

Illuminating Interactions: Visual State In Jetpack Compose

  • May 20, 2023
View Post
  • Computing
  • Data
  • Programming
  • Software
  • Software Engineering

The Top 10 Data Interchange Or Data Exchange Format Used Today

  • May 11, 2023
View Post
  • Architecture
  • Programming
  • Public Cloud

From Receipts To Riches: Save Money W/ Google Cloud & Supermarket Bills – Part 1

  • May 8, 2023
View Post
  • Programming
  • Public Cloud

3 New Ways To Authorize Users To Your Private Workloads On Cloud Run

  • May 4, 2023
View Post
  • Programming
  • Public Cloud

Buffer HTTP Requests With Cloud Tasks

  • May 4, 2023
View Post
  • Programming
  • Public Cloud
  • Software
  • Software Engineering

Learn About Google Cloud’s Updated Renderer For The Maps SDK For Android

  • May 4, 2023

Stay Connected!
LATEST
  • 1
    Just make it scale: An Aurora DSQL story
    • May 29, 2025
  • 2
    Reliance on US tech providers is making IT leaders skittish
    • May 28, 2025
  • Examine the 4 types of edge computing, with examples
    • May 28, 2025
  • AI and private cloud: 2 lessons from Dell Tech World 2025
    • May 28, 2025
  • 5
    TD Synnex named as UK distributor for Cohesity
    • May 28, 2025
  • Weigh these 6 enterprise advantages of storage as a service
    • May 28, 2025
  • 7
    Broadcom’s ‘harsh’ VMware contracts are costing customers up to 1,500% more
    • May 28, 2025
  • 8
    Pulsant targets partner diversity with new IaaS solution
    • May 23, 2025
  • 9
    Growing AI workloads are causing hybrid cloud headaches
    • May 23, 2025
  • Gemma 3n 10
    Announcing Gemma 3n preview: powerful, efficient, mobile-first AI
    • May 22, 2025
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • Understand how Windows Server 2025 PAYG licensing works
    • May 20, 2025
  • By the numbers: How upskilling fills the IT skills gap
    • May 21, 2025
  • 3
    Cloud adoption isn’t all it’s cut out to be as enterprises report growing dissatisfaction
    • May 15, 2025
  • 4
    Hybrid cloud is complicated – Red Hat’s new AI assistant wants to solve that
    • May 20, 2025
  • 5
    Google is getting serious on cloud sovereignty
    • May 22, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.