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

Android中ByteBuddy无法定位okhttp3.OkHttpClient类文件求助

如何用ByteBuddy自动替换所有OkHttpClient实例?

此前按建议修改代码后,子类方式可正常运行,但尝试用ByteBuddy重定义OkHttpClient实现全局替换时遇到错误,具体信息如下:

现有代码

1. ByteBuddy初始化代码

fun setupOkHttpBuilderByteBuddy(context: Context) {
    val strategy = AndroidClassLoadingStrategy.Wrapping(
        context.getDir("generated", Context.MODE_PRIVATE)
    )

    try {
        val classLoader = context.classLoader ?: OkHttpClient::class.java.classLoader

        val dynamicType = ByteBuddy().with(TypeValidation.DISABLED)
            .redefine(OkHttpClient::class.java)
            .method(ElementMatchers.named("newCall"))
            .intercept(MethodDelegation.to(OkHttpInterceptor::class.java))
            .make()
            .load(classLoader, strategy)
            .loaded

        Log.d("OkHttpInterceptor", "ByteBuddy modification completed")

        val instance = dynamicType.getDeclaredConstructor().newInstance()
        // 打印类名验证是否为动态生成的类
        Log.d("OkHttpInterceptor", "Class name of instance: ${instance::class.java.name}")

        // 检查实例是否为OkHttpClient的子类
        val isSubclass = OkHttpClient::class.java.isAssignableFrom(instance::class.java)
        Log.d("OkHttpInterceptor", "Is instance a subclass of OkHttpClient? $isSubclass")

    } catch (e: Exception) {
        e.printStackTrace()
    }
}

2. OkHttpInterceptor代码

class OkHttpInterceptor {

    companion object {
        @JvmStatic
        fun intercept(
            @SuperCall originalCall: Callable<Call>,
            @Argument(0) request: Request
        ): Call {
            // 日志或修改请求逻辑
            Log.d("OkHttpInterceptor", "Intercept method request: $request")

            val client = OkHttpClient.Builder()
                .addInterceptor(NetworkInterceptor())
                .build()

            // 调用原始方法并传入修改后的请求
//            return originalCall.call()
            return client.newCall(request)
        }
    }
}

遇到的错误(翻译后)

java.lang.IllegalStateException: 无法找到okhttp3.OkHttpClient的类文件
at net.bytebuddy.dynamic.ClassFileLocator$Resolution$Illegal.resolve(ClassFileLocator.java:130)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:4034)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:2246)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$UsingTypeWriter.make(DynamicType.java:4057)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3741)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3993)
at com.rnadigital.monita_android.MyApplicationKt.setupOkHttpBuilderByteBuddy(MyApplication.kt:90)
at com.rnadigital.monita_android.MyApplication.onCreate(MyApplication.kt:33)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6998)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

加载信息:已加载/vendor/lib64/egl/libEGL_emulation.so

解决方案建议

  1. 确保类文件可被定位:
    ByteBuddy重定义类时需要访问原始类的class文件,Android环境中OkHttpClient来自外部依赖,需显式指定类加载器定位class文件。修改重定义代码:

    val dynamicType = ByteBuddy().with(TypeValidation.DISABLED)
        .redefine(OkHttpClient::class.java, ClassFileLocator.ForClassLoader.of(classLoader))
        .method(ElementMatchers.named("newCall"))
        .intercept(MethodDelegation.to(OkHttpInterceptor::class.java))
        .make()
        .load(classLoader, strategy)
        .loaded
    
  2. 使用Agent方式实现全局拦截:
    Android环境下全局替换所有OkHttpClient实例,更可靠的方式是用ByteBuddy Agent在类加载阶段转换代码,而非运行时重定义。可通过AndroidClassLoadingStrategy.Injection配置Agent,确保所有后续加载的OkHttpClient类都被修改。

  3. 修复Interceptor循环调用问题:
    当前Interceptor中新建OkHttpClient实例会导致循环拦截,建议修改请求后直接调用原始方法:

    @JvmStatic
    fun intercept(
        @SuperCall originalCall: Callable<Call>,
        @Argument(0) request: Request
    ): Call {
        Log.d("OkHttpInterceptor", "Intercept method request: $request")
        // 修改请求示例:添加自定义Header
        val modifiedRequest = request.newBuilder()
            .addHeader("X-Custom-Header", "ByteBuddy-Intercepted")
            .build()
        // 调用原始方法,避免创建新实例引发循环
        return originalCall.call()
    }
    
  4. 确认类加载器权限:
    优先使用应用上下文类加载器,避免使用OkHttpClient自身类加载器导致的权限或类定位问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:42:05