Mobile Development 16 min read

Mastering Gradle: Lifecycle, Tasks, and Plugin Development for Android

This comprehensive guide walks through Gradle fundamentals—including the initialization, configuration, and execution phases—explains task creation, ordering, and incremental builds, demonstrates custom tasks and small examples, and shows three ways to build and publish Gradle plugins with ASM bytecode instrumentation for Android projects.

Huolala Tech
Huolala Tech
Huolala Tech
Mastering Gradle: Lifecycle, Tasks, and Plugin Development for Android

Gradle Basics

Gradle Lifecycle

Gradle's build process consists of three distinct phases: initialization, configuration, and execution.

1. Initialization Phase

In this phase Gradle determines which projects participate in the build and creates a Project instance for each. It reads the settings.gradle file to identify the project structure.

2. Configuration Phase

Gradle configures each project object by executing the build scripts. Tasks, dependencies, and build rules are defined, and the build.gradle file is parsed to generate a task dependency graph.

3. Execution Phase

Gradle selects the subset of tasks to run based on the command line and executes them in order, respecting dependencies. The clean task is an example that does not trigger the lifecycle when Gradle syncs.

Gradle Tasks

A Task is the basic unit of work in a Gradle build. It can compile code, copy files, run tests, etc.

1. Creating/Locating Tasks

// create task in several ways
tasks.register("taskName") { /* ... */ }

task taskName { /* ... */ }

tasks.create("taskName") { /* ... */ }

2. Custom Tasks

Extend DefaultTask, annotate a method with @TaskAction, and specify the task class when creating the task.

/**
 * Custom task
 */
class MyTask extends org.gradle.api.DefaultTask {
    @TaskAction
    void run() {
        println "custom task execution"
    }
}

task myTask(type: MyTask)

3. Task Ordering

Use dependsOn, finalizedBy, and mustRunAfter to control execution order.

hello.dependsOn(test1)
hello.finalizedBy(test2)
hello.setMustRunAfter(test3)

4. Task Input/Output (Incremental Build)

Gradle checks if task inputs have changed; if not, the task is marked UP-TO-DATE and skipped, improving build speed.

5. Task Listeners

Register callbacks before and after task execution.

void beforeTask(Action<Task> action);
void afterTask(Closure closure);

Gradle Plugins

Three Ways to Create Plugins

1. In build.gradle

Define a plugin class implementing Plugin<Project> and apply it with apply plugin: MyPlugin.

class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        println "apply plugin"
        project.task('pluginTask') {
            doLast { println 'execute plugin task' }
        }
    }
}
apply plugin: MyPlugin

2. buildSrc Project

Place plugin source code under buildSrc/src/main/java (or groovy/kotlin). Gradle compiles it and makes it available to the build scripts.

Steps:

Create a buildSrc directory.

Add a build.gradle file with a dependency on the Gradle API.

Create the plugin class.

Add a META-INF/gradle-plugins descriptor.

3. Standalone Project

Develop a separate project that produces a JAR containing the plugin, publish it, and apply it in other builds.

Small Example: Print Task Execution Time

def map = new HashMap<String, Long>()

tasks.beforeTask { Task task ->
    map.put(task.name, System.currentTimeMillis())
}

tasks.afterTask { Task task ->
    def time = map.get(task.name)
    map.put(task.name, System.currentTimeMillis() - time)
}

gradle.buildFinished {
    println "buildFinished"
    map.forEach { k, v -> println "taskName:" + k + " time:" + v }
}

Small Example: Print Task Dependency Graph

gradle.projectsEvaluated {
    println "projectsEvaluated"
    TaskExecutionGraph tasks = gradle.getTaskGraph()
    tasks.whenReady {
        println "TaskExecutionGraph whenReady"
        TaskExecutionGraph tasks2 = gradle.getTaskGraph()
        println "digraph pic { "
        List<Task> taska = tasks2.getAllTasks()
        for (i in (taska.size())..<0) {
            Task t = taska.get(i - 1)
            Set<? extends Task> dependsOn = t.getTaskDependencies().getDependencies()
            dependsOn.forEach { dt ->
                println dt.name + " -> " + t.name
            }
        }
        println "}"
    }
}

Gradle Application (ASM Instrumentation)

Instrumentation Overview

ASM is a bytecode instrumentation library. In Android builds, before converting classes to dex, a transform task can modify class files.

Debugging Gradle

Configure remote debugging in the IDE, add JVM arguments to gradle.properties, and run the debug task.

Transform logic resides in TaskManager.createPostCompilationTasks

Transform Implementation

Register a custom Transform in the plugin, iterate over class files and JARs, and modify bytecode using ASM.

public class TransformPlugin implements Plugin<Project> {
    @Override
    public void apply(Project target) {
        BaseExtension android = target.getExtensions().getByType(BaseExtension.class);
        android.registerTransform(new TransformTemplate("MyTransform", false, new MyTransform()));
    }
}

public class MyTransform implements BiConsumer<InputStream, OutputStream> {
    @Override
    public void accept(InputStream inputStream, OutputStream outputStream) {
        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        ClassVisitor visitor = writer;
        visitor = new OkHttpAdapter(visitor);
        try {
            ClassReader cr = new ClassReader(inputStream);
            cr.accept(visitor, ClassReader.EXPAND_FRAMES);
            outputStream.write(writer.toByteArray());
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }
    // additional helper methods omitted for brevity
}

Method Adapter Example

private static final class MethodAdapter extends MethodVisitor implements Opcodes {
    public MethodAdapter(MethodVisitor mv) {
        super(ASM7, mv);
    }
    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
        if (owner.equals(OKHTTP3_BUILDER_CLASS) && isConstructor(opcode, name, desc) && !itf) {
            super.visitInsn(DUP);
            super.visitMethodInsn(opcode, owner, name, desc, itf);
            invoke(OKHTTP3_WRAPPER, "addInterceptorToBuilder", "(Ljava/lang/Object;)V");
        } else if (owner.equals(OKHTTP2_CLIENT_CLASS) && isConstructor(opcode, name, desc) && !itf) {
            super.visitInsn(DUP);
            super.visitMethodInsn(opcode, owner, name, desc, itf);
            invoke(OKHTTP2_WRAPPER, "addInterceptorToClient", "(Ljava/lang/Object;)V");
        } else {
            super.visitMethodInsn(opcode, owner, name, desc, itf);
        }
    }
    private static boolean isConstructor(int opcode, String name, String desc) {
        return opcode == INVOKESPECIAL && name.equals("<init>") && desc.equals("()V");
    }
    private void invoke(String wrapper, String method, String desc) {
        super.visitMethodInsn(INVOKESTATIC, wrapper, method, desc, false);
    }
}

Interceptor Insertion

Static helper methods add interceptors to OkHttp builders or clients.

@JvmStatic
fun addInterceptorToBuilder(builder: Any?) {
    if (builder is OkHttpClient.Builder) {
        builder.addInterceptor(OkHttp3TrackInterceptor())
    }
}

@JvmStatic
fun addInterceptorToClient(client: Any?) {
    if (client is OkHttpClient) {
        client.networkInterceptors().add(OkHttp2Interceptor())
    }
}

With these hooks you can implement network monitoring, logging, or any custom logic.

Finally, publish the plugin using the standard Gradle plugin publishing workflow; once published it can be applied in other projects.

Now you have covered Gradle fundamentals, task management, plugin creation, and bytecode instrumentation for Android.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Build AutomationAndroidGradlePluginsASMOkHttptransformTask Lifecycle
Huolala Tech
Written by

Huolala Tech

Technology reshapes logistics

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.