skip icon indicating copy to clipboard operation
skip copied to clipboard

Crash in release builds: java.lang.NullPointerException: null cannot be cast to non-null type skip.ui.PreferenceKeyCompanion<Value of skip.ui.Preference>

Open marcprux opened this issue 1 year ago • 1 comments

When the release Showcase.apk in the emulator that uses a PreferenceKey, crashes may occur like:

02-17 23:01:30.001  2470  2470 E AndroidRuntime: FATAL EXCEPTION: main
02-17 23:01:30.001  2470  2470 E AndroidRuntime: Process: skip.showcase.App, PID: 2470
02-17 23:01:30.001  2470  2470 E AndroidRuntime: java.lang.NullPointerException: null cannot be cast to non-null type skip.ui.PreferenceKeyCompanion<Value of skip.ui.Preference>
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at ra.e3.<init>(SourceFile:2)
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at ra.e3.<init>(SourceFile:3)
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at ra.u2$i.a(Unknown Source:765)
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at ra.u2$i.p0(Unknown Source:10)
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at s0.b.e(Unknown Source:49)
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at s0.b.p0(Unknown Source:8)
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at androidx.compose.material3.g2$d$a$a.a(Unknown Source:125)
02-17 23:01:30.001  2470  2470 E AndroidRuntime: 	at androidx.compose.material3.g2$d$a$a.q0(Unknown Source:8)

This is likely coming from PreferenceKey.swift:

self.initialValue = initialValue ?? (key.companionObjectInstance as! PreferenceKeyCompanion<Value>).defaultValue

This seems to be a consequence of the release build's proguard reduction. Changing the Android/app/proguard-rules.pro file to exclude skip classes makes the crash go away:

-keep class skip.** { *; }
-keep class showcase.module.** { *; }

However, it also increases the Showcase-release.apk size to 15.5 MB from 11.1 MB. Similarly, HelloSkip-release.apk jumps from 6.2 MB to 11 MB, which is an undesirable increase in minimum app size.

I suspect this is due to the way kotlin.reflect.full.companionObjectInstance works. I wonder if it would be possible to avoid using reflection to get the companion object, maybe by using @JvmStatic instead.

marcprux avatar Feb 18 '24 04:02 marcprux

Some hints from https://github.com/Kotlin/kotlinx.serialization/issues/1129 and https://github.com/Kotlin/kotlinx.serialization/issues/1121 could yield a narrower set of proguard rules might work around this issue

marcprux avatar Feb 18 '24 15:02 marcprux