Kotlin混淆后KFunction.callBy报错:需2参数却传1(DefaultConstructorMarker问题)
问题
在开启代码混淆的Kotlin环境里,用KFunction.callBy动态调用构造函数时出问题了:没开混淆时代码正常运行,一开混淆就报错,错误信息是Callable expects 2 arguments, but 1 were provided。排查后发现,constructor.caller.parameterTypes里多出来一个DefaultConstructorMarker类型的参数。
代码示例
data class User( val name: String ) private fun <T> buildObject( ... constructor: KFunction<T>, ): T { val params = constructor.valueParameters.mapIndexed { index, param -> val res = getValueForParam() param to res }.toMap() return constructor.callBy(params) }
报错信息
Callable expects 2 arguments, but 1 were provided
当前使用的ProGuard规则
-keepattributes *Annotation*, Signature, InnerClasses, Synthetic, MethodParameters, RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations, Record, InnerClasses, EnclosingMethod -keep class my.package.** { *;<init>(...); } -keepclassmembers class my.package.**$* { *; } -keepclassmembernames class my.package.**$* { *; } -keep class kotlin.Metadata { *; }
解决方案
问题根源是混淆过程中,Kotlin编译自动生成的带DefaultConstructorMarker参数的合成构造函数元数据被破坏,导致KFunction错把这个内部专用参数当成了需要手动传入的普通参数。
调整ProGuard规则,补充以下内容:
# 保留目标包下类的构造函数及参数信息,避免合成构造函数元数据丢失 -keepclassmembers class my.package.** { <init>(...); @kotlin.jvm.JvmOverloads <init>(...); } # 保留Kotlin内部的DefaultConstructorMarker类,禁止混淆工具修改或移除它 -keep class kotlin.jvm.internal.DefaultConstructorMarker { *; } # 确保Kotlin反射所需的元数据完整保留 -keepattributes KotlinMetadata
另外注意:原规则里的-keepattributes已经包含Synthetic,但部分版本的ProGuard需要显式指定KotlinMetadata属性,才能保证Kotlin反射依赖的元数据不被混淆破坏。
内容的提问来源于stack exchange,提问作者NonceWizard
相关产品推荐
相关产品推荐

