R8 去除反射所需的 Kotlin 伴生对象

Posted

技术标签:

【中文标题】R8 去除反射所需的 Kotlin 伴生对象【英文标题】:R8 stripping out Kotlin companion object needed for reflection 【发布时间】:2020-01-18 08:04:03 【问题描述】:

我有一个带有实现工厂接口的伴随对象的类。

class GoalInspectorData(
    ...
) 

    companion object : DataClassFactory<GoalInspectorData> 

        override fun fromV8Object(v8Object: V8Object): GoalInspectorData 
            ...
        
    

我有一些代码在运行时使用反射检查此类,以查看该类是否提供工厂方法。它通过检查该类是否具有伴随对象 (companionObjectInstance) 以及如果有,则该伴随对象是否实现工厂接口来实现这一点。

internal inline fun <reified T> convert(obj: Any): T 

    val companionObject = T::class.companionObjectInstance

    @Suppress("UNCHECKED_CAST")
    return when 
        T::class in builtInClasses -> obj as T
        companionObject as? DataClassFactory<T> != null -> companionObject.fromV8Object(obj as V8Object)
        else -> throw IllegalArgumentException("No converter for type $T::class")
    

这在调试版本中一切正常。

在启用 R8 的发布构建中失败(build.gradle 中的minifyEnabled true)。它失败了,因为companionObjectInstance 返回null

我正在使用 不优化 Proguard 配置:

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

在我自己的 proguard-rules.pro 中,我添加了几乎所有我能想象到的 -keep 规则,试图保留这个伴随对象,并为所有内容添加了 @Keep 注释,但没有任何效果。 R8决心将其剥离。

例如:

-keep class my.package.** 
    *;

-keep interface my.package.** 
    *;


-if class **$Companion extends **
-keep class <2>
-if class **$Companion implements **
-keep class <2>

是否有任何其他 -keep 规则或配置选项可以指示 R8 保留此伴随对象?

【问题讨论】:

你试过添加@Keep注解吗? @RobCo 是的,没有区别。 【参考方案1】:

首先,保持规则

-keep class my.package.** 
    *;

应该足以保留所有类 - 包括程序中的伴随类。您应该不需要-dontoptimize 标志,因此使用配置proguard-android-optimize.txt 应该没问题。

但是,当您使用 Kotlin 反射时,您可能还需要使用以下规则保持注解类 kotlin.Metadata 和运行时可见注解:

-keep @interface kotlin.Metadata 
  *;

-keepattributes RuntimeVisibleAnnotations

如果还是不行,请提交R8 issue 吗?如果你能包含一个简单的复制,那就太好了。

【讨论】:

以上是关于R8 去除反射所需的 Kotlin 伴生对象的主要内容,如果未能解决你的问题,请参考以下文章

在 kotlin 中命名伴生对象有啥意义

深入kotlin- 伴生对象和扩展

深入kotlin- 伴生对象和扩展

深入kotlin- 伴生对象和扩展

通过 Java 反射找到 Scala 类型的伴生对象的可靠方法是啥?

通过 Java 反射找到 Scala 类型的伴生对象的可靠方法是啥?