Jetpack Compose多模块项目接口带@Composable方法报NoSuchMethodError如何解决
问题产生原因
这个错误确实和@Composable注解的编译逻辑直接相关:
Compose 编译器会给所有标注了@Composable的函数自动注入2个编译期生成的额外参数:Composer实例、状态变更标记整数,用来支撑重组逻辑、状态追踪。你遇到的方法签名不匹配,本质是Core模块和B模块的Compose编译配置不一致,导致接口编译后的方法签名和实现类的方法签名对不上:
- 绝大多数情况是Core模块没有启用Compose编译插件,接口中的
NotificationLayoutStatusState方法编译时没有被注入额外参数,生成的方法签名只有(Landroidx/compose/ui/Modifier;)V,但B模块启用了Compose编译插件,实现类的同方法编译后生成的签名是(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V,运行时找接口方法就会报错。 - 少部分情况是Core、B模块的Compose编译器版本、Kotlin版本不匹配,导致注入的参数位置/数量存在差异。
- 极小概率是开启R8混淆时没有保留对应接口的方法签名,合成的方法被混淆擦除。
解决方案
按优先级依次排查修复:
- 统一全模块Compose编译配置:Core、A、B三个模块都要启用Compose编译能力,且Kotlin版本、Compose编译器扩展版本完全保持一致。
所有模块的build.gradle.kts(Groovy语法同理)都要添加以下配置:android { buildFeatures { // 启用Compose编译 compose = true } composeOptions { // 版本要全局统一,且和当前项目的Kotlin版本匹配 kotlinCompilerExtensionVersion = "你的统一版本号" } } - 补充混淆规则:如果项目开启了代码混淆(
minifyEnabled=true),在proguard规则文件中添加对应接口的保留规则,避免合成方法被擦除:# 替换为你实际的接口包名 -keep interface com.xxx.xxx.NotificationLayout { *; } -keep class * implements com.xxx.xxx.NotificationLayout { *; } - 验证方法签名:可以直接在Core模块的任意Composable函数中调用一次该接口的
NotificationLayoutStatusState方法,重新打包后如果编译不报错说明Core模块的Compose配置已经生效,运行时异常也会同步消失。
内容的提问来源于stack exchange,提问作者Susan Thapa
相关产品推荐
相关产品推荐

