In my current Kotlin Android project I just had to face the following problem:
For this class hierarchy
abstract class MyClass {
...
}
class MySubClassA: MyClass() {
...
}
class MySubClassB: MyClass() {
...
}
class MySubClassC: MyClass() {
...
}
I wrote a creator function like this:
private fun <T : MyClass> createMyClass(myClassType: KClass<T>): T? {
val constructor = myClassType.primaryConstructor
return constructor?.call()?.apply {
...
}
}
This worked nicely for the debug version but for the release version with R8 obfuscation turned on the constructor was alway null
. My settings for R8 were this:
-keep class kotlin.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn kotlin.**
-keepclassmembers class **$WhenMappings {
<fields>;
}
-keepclassmembers class kotlin.Metadata {
public <methods>;
}
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
-keep class kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoaderImpl
After some reverse engineering of the Kotlin reflection API I came up with the following workaround:
private fun <T : MyClass> createMyClass(myClassType: KClass<T>): T? {
val constructor = myClassType.constructors.firstOrNull() {
it.valueParameters.isEmpty()
}
return constructor?.call()?.apply {
...
}
}
This seems to indicate, that the constructor information of the class is preserved by R8 but the meta information about a constructor being primary gets lost.
Does anybody know how to solve this in general?
I came across this issue and was able to resolve it using the @Keep
annotation.
abstract class MyClass {
}
class MySubClassA @Keep constructor(): MyClass() {
}
class MySubClassB @Keep constructor(): MyClass() {
}
class MySubClassC @Keep constructor(): MyClass() {
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.