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  Android Studio Flamingo Is Stable

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  Android 13 Developer Preview 2

./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  Making Jellyfish Move In Compose: Animating ImageVectors And Applying AGSL RenderEffects 🐠

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
  • college-of-cardinals-2025 1
    The Definitive Who’s Who of the 2025 Papal Conclave
    • May 7, 2025
  • conclave-poster-black-smoke 2
    The World Is Revalidating Itself
    • May 6, 2025
  • 3
    Conclave: How A New Pope Is Chosen
    • April 25, 2025
  • Getting things done makes her feel amazing 4
    Nurturing Minds in the Digital Revolution
    • April 25, 2025
  • 5
    AI is automating our jobs – but values need to change if we are to be liberated by it
    • April 17, 2025
  • 6
    Canonical Releases Ubuntu 25.04 Plucky Puffin
    • April 17, 2025
  • 7
    United States Army Enterprise Cloud Management Agency Expands its Oracle Defense Cloud Services
    • April 15, 2025
  • 8
    Tokyo Electron and IBM Renew Collaboration for Advanced Semiconductor Technology
    • April 2, 2025
  • 9
    IBM Accelerates Momentum in the as a Service Space with Growing Portfolio of Tools Simplifying Infrastructure Management
    • March 27, 2025
  • 10
    Tariffs, Trump, and Other Things That Start With T – They’re Not The Problem, It’s How We Use Them
    • March 25, 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
  • 1
    IBM contributes key open-source projects to Linux Foundation to advance AI community participation
    • March 22, 2025
  • 2
    Co-op mode: New partners driving the future of gaming with AI
    • March 22, 2025
  • 3
    Mitsubishi Motors Canada Launches AI-Powered “Intelligent Companion” to Transform the 2025 Outlander Buying Experience
    • March 10, 2025
  • PiPiPi 4
    The Unexpected Pi-Fect Deals This March 14
    • March 13, 2025
  • Nintendo Switch Deals on Amazon 5
    10 Physical Nintendo Switch Game Deals on MAR10 Day!
    • March 9, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.