You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改依赖库中Gradle Task的实现以适配配置缓存?

解决依赖库中Gradle任务的配置缓存问题(MPManifestTask场景)

问题描述

Android项目使用Gradle构建,依赖的库A包含MPManifestTask任务,每次构建都会执行。开启Gradle配置缓存后,构建日志报错:

task:app:mpProcessItDebugit-debugManifest of type com.alipay.mpaas.easy.config.MPManifestTask
invocation of Task.project at execution time is unsupported. invocation of Task.project at execution time is unsupported.

查看该任务的核心实现代码:

@TaskAction
public void executeTask() throws Exception {
    Logger logger = this.getProject().getLogger();
    logger.info("======================ANDROIDMANIFEST CONVERTER START================================");
    logger.info(" start to convert" + this.appAndroidManifestFile);
}

问题根源是Gradle配置缓存禁止在任务执行阶段调用getProject(),正确的做法是直接使用任务自身的getLogger()方法,但无法直接修改依赖库的源码,需要通过其他方式修复。


可行解决方案

方案1:替换任务实现(推荐)

创建一个修复后的自定义任务,替换依赖库中的原任务,保留原有逻辑的同时修复配置缓存问题。

步骤1:在buildSrc中定义修复任务

在项目的buildSrc模块(若没有则新建)中创建自定义任务类,复制原任务的属性和逻辑,仅修改日志获取方式:

import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.logging.Logger;

public class FixedMPManifestTask extends DefaultTask {
    @InputFile
    private File appAndroidManifestFile;

    public File getAppAndroidManifestFile() {
        return appAndroidManifestFile;
    }

    public void setAppAndroidManifestFile(File appAndroidManifestFile) {
        this.appAndroidManifestFile = appAndroidManifestFile;
    }

    @TaskAction
    public void executeTask() throws Exception {
        Logger logger = getLogger(); // 替换为任务自身的getLogger()
        logger.info("======================ANDROIDMANIFEST CONVERTER START================================");
        logger.info(" start to convert" + this.appAndroidManifestFile);
        // 若原任务有其他逻辑,完整复制过来
    }
}

步骤2:在App模块中替换任务

在app/build.gradle中添加任务替换逻辑,禁用原任务并让依赖链指向修复后的任务:

tasks.withType(com.alipay.mpaas.easy.config.MPManifestTask) { originalTask ->
    // 创建修复后的任务
    def fixedTaskName = "fixed${originalTask.name.capitalize()}"
    def fixedTask = tasks.create(fixedTaskName, FixedMPManifestTask) {
        // 复制原任务的输入输出和属性
        appAndroidManifestFile = originalTask.appAndroidManifestFile
        inputs.files originalTask.inputs.files
        outputs.files originalTask.outputs.files
        // 复制依赖关系
        dependsOn originalTask.dependsOn
        mustRunAfter originalTask.mustRunAfter
    }

    // 禁用原任务
    originalTask.enabled = false

    // 将所有依赖原任务的任务改为依赖修复任务
    tasks.matching { it.dependsOn.contains(originalTask) }.each { dependentTask ->
        dependentTask.dependsOn fixedTask
    }
}

方案2:字节码增强动态修改

如果原任务逻辑复杂,复制成本高,可以使用ASM字节码框架在类加载时动态修改executeTask方法,替换违规调用。

步骤1:在buildSrc中添加ASM依赖

// buildSrc/build.gradle
dependencies {
    implementation 'org.ow2.asm:asm:9.5'
    implementation 'org.ow2.asm:asm-commons:9.5'
}

步骤2:编写类转换逻辑

创建Gradle插件,注册类转换器,修改MPManifestTask的字节码:

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

public class MPManifestFixPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        // 拦截类加载,修改MPManifestTask的字节码
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        try {
            // 读取原类字节码
            InputStream is = classLoader.getResourceAsStream("com/alipay/mpaas/easy/config/MPManifestTask.class");
            ClassReader cr = new ClassReader(is);
            ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);

            ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) {
                @Override
                public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                    MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
                    // 只处理executeTask方法
                    if ("executeTask".equals(name) && "()V".equals(desc)) {
                        return new MethodVisitor(Opcodes.ASM9, mv) {
                            @Override
                            public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean isInterface) {
                                // 替换this.getProject().getLogger()为this.getLogger()
                                if (opcode == Opcodes.INVOKEVIRTUAL && "getProject".equals(methodName)) {
                                    // 跳过getProject()调用
                                    return;
                                }
                                if (opcode == Opcodes.INVOKEVIRTUAL && "getLogger".equals(methodName) && owner.equals("org/gradle/api/Project")) {
                                    // 将调用目标改为当前任务类
                                    super.visitMethodInsn(opcode, "com/alipay/mpaas/easy/config/MPManifestTask", methodName, "()Lorg/gradle/api/logging/Logger;", false);
                                    return;
                                }
                                super.visitMethodInsn(opcode, owner, methodName, methodDesc, isInterface);
                            }
                        };
                    }
                    return mv;
                }
            };

            cr.accept(cv, ClassReader.EXPAND_FRAMES);
            byte[] modifiedClassBytes = cw.toByteArray();

            // 利用反射将修改后的类注入类加载器
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);
            Map<String, Class<?>> classes = (Map<String, Class<?>>) field.get(classLoader);
            classes.remove("com.alipay.mpaas.easy.config.MPManifestTask");

            // 重新加载修改后的类
            Method defineMethod = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
            defineMethod.setAccessible(true);
            defineMethod.invoke(classLoader, "com.alipay.mpaas.easy.config.MPManifestTask", modifiedClassBytes, 0, modifiedClassBytes.length);

        } catch (Exception e) {
            project.getLogger().error("Failed to fix MPManifestTask: ", e);
        }
    }
}

步骤3:应用插件

在settings.gradle中配置插件仓库,然后在app/build.gradle中应用:

// settings.gradle
pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenLocal()
    }
}

// app/build.gradle
plugins {
    id 'com.android.application'
    id 'your.package.mp-manifest-fix'
}

方案3:提交修复PR(最彻底)

如果该依赖库是开源项目,直接修改源码将this.getProject().getLogger()改为this.getLogger(),提交PR给维护者,等待合并后升级依赖版本即可。


内容的提问来源于stack exchange,提问作者jim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:34:55