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

使用Byte-Buddy Android Gradle Plugin拦截方法失败,寻求解决办法

问题分析与解决方案

核心原因

你遇到的UnsupportedOperationException: Cannot intercept method for decorated type错误,是因为Byte Buddy Android插件默认使用**DECORATE(装饰)转换策略——该策略通过创建子类来包装原类,无法直接拦截或修改原类的方法实现。而你尝试的withToString()、method().intercept()等操作,需要直接修改原类字节码,必须使用REDEFINE(重定义)**策略。

解决步骤

1. 修改Gradle配置,切换到REDEFINE策略

在你的模块级build.gradle.kts(或build.gradle)中添加Byte Buddy配置,指定转换策略为REDEFINE:

Kotlin DSL

byteBuddy {
    transformationStrategy = net.bytebuddy.android.TransformationStrategy.REDEFINE
}

Groovy

byteBuddy {
    transformationStrategy = 'REDEFINE'
}

2. 修正插件代码,正确拦截方法

withToString()是用于创建新类时生成toString方法的快捷方式,不适用于修改已有类。需要显式匹配目标方法并替换其实现:

示例1:直接替换toString返回值

import net.bytebuddy.implementation.FixedValue
import net.bytebuddy.matcher.ElementMatchers.named

class AnalyticsPlugin : Plugin {

    override fun matches(target: TypeDescription): Boolean {
        return target.canonicalName?.contains("TestClass") == true
    }

    override fun close() {}

    override fun apply(
        builder: DynamicType.Builder<*>,
        typeDescription: TypeDescription,
        classFileLocator: ClassFileLocator
    ): DynamicType.Builder<*> {
        // 拦截toString方法并替换返回值
        return builder.method(named("toString"))
            .intercept(FixedValue.value("Modified TestClass{2}"))
    }
}

示例2:使用方法委托(MethodDelegation)

如果你需要更复杂的逻辑(比如调用原方法后追加内容),可以使用委托类:

首先定义拦截器类:

import net.bytebuddy.implementation.bind.annotation.Origin
import net.bytebuddy.implementation.bind.annotation.RuntimeType
import net.bytebuddy.implementation.bind.annotation.This
import java.lang.reflect.Method

class ToStringInterceptor {
    @RuntimeType
    fun intercept(@Origin method: Method, @This obj: Any): String {
        // 调用原方法获取结果
        val originalResult = method.invoke(obj)
        // 追加自定义内容
        return "[$originalResult] (Modified by Byte Buddy)"
    }
}

然后修改插件代码:

import net.bytebuddy.implementation.MethodDelegation
import net.bytebuddy.matcher.ElementMatchers.named

class AnalyticsPlugin : Plugin {

    override fun matches(target: TypeDescription): Boolean {
        return target.canonicalName?.contains("TestClass") == true
    }

    override fun close() {}

    override fun apply(
        builder: DynamicType.Builder<*>,
        typeDescription: TypeDescription,
        classFileLocator: ClassFileLocator
    ): DynamicType.Builder<*> {
        // 使用委托类拦截toString方法
        return builder.method(named("toString"))
            .intercept(MethodDelegation.to(ToStringInterceptor::class.java))
    }
}

3. 针对注解拦截的修正

对于你提到的注解拦截场景,同样需要切换到REDEFINE策略,然后使用正确的匹配器:

import net.bytebuddy.implementation.MethodDelegation
import net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith

class AnalyticsPlugin : Plugin {

    override fun matches(target: TypeDescription): Boolean {
        return true // 或根据需要筛选目标类
    }

    override fun close() {}

    override fun apply(
        builder: DynamicType.Builder<*>,
        typeDescription: TypeDescription,
        classFileLocator: ClassFileLocator
    ): DynamicType.Builder<*> {
        // 拦截所有带有CallToAction注解的方法
        return builder.method(isAnnotatedWith(CallToAction::class.java))
            .intercept(MethodDelegation.to(Interceptor::class.java))
    }
}

关键注意事项

  • 确保拦截器类(如ToStringInterceptor、Interceptor)在Byte Buddy转换阶段已编译完成,可将其放在单独的模块或确保编译顺序优先于目标类。
  • REDEFINE策略直接修改原类字节码,是Android编译时 instrumentation 的标准做法,不会产生额外的子类开销。

内容的提问来源于stack exchange,提问作者Engin Kadir Şahin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 05:42:32