返回

伴生对象静态方法的困扰:Proguard/R8 优化后的拯救之道

Android

Proguard/R8最小化后,Kotlin伴生对象静态方法不被识别?

引言

在使用Proguard/R8对Kotlin代码进行最小化时,你可能会遇到伴生对象的静态方法不被识别的棘手问题。即使伴生对象和方法仍然存在,但如果没有引用伴生对象,就无法调用它们。本文将深入探讨这个问题,并提供一劳永逸的解决方案。

问题剖析

想象一下这种情况:你正使用R8库,但伴生对象的方法没有被识别为主类的引用。伴生对象和方法明明还在那里,但就是不能在不引用伴生对象的情况下调用它们。

代码示例:

// 可用
MyClass.Companion.foo()

// 报错,未解决引用
MyClass.foo(this)

Proguard规则:

-keep @interface kotlin.Metadata { *; }
-keepattributes RuntimeVisibleAnnotations

-keep public class com.example.MyClass {
    public <methods>;
    public static <methods>;
}
-keep public class com.example.MyClass$Companion {
    public <methods>;
}

别忘了,伴生对象的方法也被标记为@JvmStatic,并且这些静态方法确实存在于生成的代码中,但Kotlin编译器就是不肯识别它们。

成因探究

这个问题的根源在于Proguard/R8的优化机制。它会毫不留情地移除未引用的代码,包括伴生对象的静态方法。

完美解决方案

要彻底解决这个难题,我们需要在Proguard/R8配置中明确保留伴生对象的静态方法。有两种途径:

  1. 使用-keep规则:
-keepclassmembers class * {
    @kotlin.jvm.JvmStatic public static *;
}
  1. 使用-keepattributes规则:
-keepattributes *Annotation*

其他贴心提示:

  • 请务必在Proguard/R8配置中正确指定伴生对象的类名。
  • 伴生对象和方法必须标注为public,才能被Proguard/R8识别。
  • 在代码中引用伴生对象的方法至关重要。

范例配置:

以下是保留伴生对象静态方法的Proguard配置:

-keep @interface kotlin.Metadata { *; }
-keepattributes RuntimeVisibleAnnotations,Signature,InnerClasses
-keepclassmembers class * {
    @kotlin.jvm.JvmStatic public static *;
}

总结

通过正确配置Proguard/R8,你可以高枕无忧,因为伴生对象的静态方法在最小化后仍然会被识别。借助本文提供的解决方案,你可以在保持代码精简的同时,尽情发挥Kotlin伴生对象强大的功能。

常见问题解答

  1. 为什么我的伴生对象静态方法在Proguard/R8最小化后不被识别?

答:Proguard/R8会移除未引用的代码,包括伴生对象的静态方法。

  1. 如何解决这个问题?

答:你可以使用-keep-keepattributes规则来保留伴生对象的静态方法。

  1. 伴生对象和方法必须是public的吗?

答:是的,伴生对象和方法必须标注为public,才能被Proguard/R8识别。

  1. 我在代码中引用了伴生对象的方法,但仍然遇到问题?

答:请确保在Proguard/R8配置中正确指定了伴生对象的类名。

  1. 在配置Proguard/R8时,还有什么需要注意的吗?

答:请确保-keep-keepattributes规则位于配置文件的末尾。