skiptools / skip

Skip transpiler for creating SwiftUI apps for iOS and Android

Home Page:https://skip.tools

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

marcprux opened this issue · 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.

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