背景

如题,我的结论是在 xposed 模块里面网络请求不要使用 retrofit。或者其实是可以用的,但是至少很容易出问题,所以还是避免的好,直接用 okhttp 和 ktor 都行。

关于这个问题,我已经搞了好几天了。

一开始我用 retrofit 来实现 xposed 模块内网络请求,遇到 call adapter 错误

我的修复过程:

  • 我几乎看过所有 csdn 和 stateflow 上的讨论,包括导入特定的 call adapter,结果都没用,但是在主应用进行网络请求根本不会有这个问题
  • 我以为是因为目标 hook 应用里面也有 retrofit,而且是 api 不兼容的版本才导致这个问题,所以我又用 shadowJar 来改 retrofit 的包名,改完编译完还是不行
  • 现在完全移除 retrofit2 依赖,用纯 okhttp 实现,终于解决!

总得来说,在 Xposed 这种特殊的运行环境中,问题往往比想象的要更深一些。


gemini-2.5-pro 的看法:

这通常不是简单的类名冲突,而是和 ClassLoader(类加载器)以及反射(Reflection)机制的复杂交互有关。

  1. Retrofit 的工作原理:Retrofit 在背后做了大量的反射工作来解析您定义的 IChatService 接口、方法注解 (@POST) 和返回值类型(比如 suspend 函数或者 Flow<>)。它需要根据这些信息动态地创建一个实现类,并找到合适的 CallAdapter 来处理异步调用。

  2. Xposed 的环境:在 Xposed 模块中,您的代码是被注入到目标应用的进程里运行的。这意味着您的代码和目标应用共享一个非常复杂的运行时环境和 ClassLoader。

  3. 问题的根源:当您的 Retrofit 实例试图进行反射操作时,很可能受到了目标应用已加载的类(包括它自己的旧版 Retrofit/OkHttp,甚至是其他库)的干扰。这种干扰会导致 Retrofit 的 CallAdapter.Factory 无法正确识别或创建处理 suspend 函数所需适配器,从而抛出错误。shadowJar 能解决类名冲突,但解决不了这种深层的 ClassLoader 和反射逻辑的混乱。

而当您换用纯 OkHttp 后,您等于完全绕过了 Retrofit 整个复杂的“接口定义 -> 反射 -> 动态代理 -> 创建请求”的流程。

您现在是在直接、显式地构建一个 Request 对象,然后把它交给 OkHttpClient 执行。这个过程清晰明了,几乎不涉及复杂的反射,因此在任何环境下都非常稳定、可靠。


结论

在复杂环境下开发,不管是自己进行反射操作,还是使用大量使用反射的第三方库,都要谨慎,不然遇到类似这样的问题真的太搞了

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐