Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRITICAL BUG using java.time.Instant which is not available in API below 26 #8

Closed
wakaztahir opened this issue May 30, 2023 · 6 comments · Fixed by #10
Closed

CRITICAL BUG using java.time.Instant which is not available in API below 26 #8

wakaztahir opened this issue May 30, 2023 · 6 comments · Fixed by #10

Comments

@wakaztahir
Copy link

Here are two exceptions , I updated the app with the library to min Sdk 21 and my users are getting this exception , I found this using Firebase Crashlytics

Since
https://stackoverflow.com/questions/52510370/java-lang-noclassdeffounderror-failed-resolution-of-ljava-time-localdate-erro

Please instead of using Kotlinx date time library to get the current time Millis , Use the expect actual functions , Please update the library as soon as possible , We have a lot of users who have this bug

Caused by java.lang.ClassNotFoundException: Didn't find class "java.time.Instant" on path: DexPathList[[zip file "/data/app/com.wakaztahir.mindnode-1/base.apk", zip file "/data/app/com.wakaztahir.mindnode-1/split_config.es.apk", zip file "/data/app/com.wakaztahir.mindnode-1/split_config.xhdpi.apk"],nativeLibraryDirectories=[/data/app/com.wakaztahir.mindnode-1/lib/arm, /system/lib, /vendor/lib]]
       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
       at kotlinx.datetime.Instant.<clinit>(Instant.kt:96)
       at kotlinx.datetime.Clock$System.now(Clock.kt:25)
       at com.chrynan.navigation.NavigationEvent$Forward$Destination.<init>(NavigationEvent.kt:105)
       at com.chrynan.navigation.NavigatorKt.goTo(Navigator.kt:107)
       at com.wakaztahir.mindnode.ui.components.main.MainScreenKt$MainScreen$1$1$1$2.invoke(MainScreen.kt:116)
       at com.wakaztahir.mindnode.ui.components.main.MainScreenKt$MainScreen$1$1$1$2.invoke(MainScreen.kt:102)
       at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke-k-4lQ0M(Clickable.kt:167)
       at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke(Clickable.kt:156)
       at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1.invokeSuspend(TapGestureDetector.kt:255)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:177)
       at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
       at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:368)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:566)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:456)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:469)
       at androidx.compose.ui.node.BackwardsCompatNode.onPointerEvent-H0pRuoY(BackwardsCompatNode.kt:374)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:314)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:183)
       at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:102)
       at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:98)
       at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1361)
       at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1307)
       at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1246)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:609)
       at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1895)
       at android.app.Activity.dispatchTouchEvent(Activity.java:3241)
       at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:571)
       at android.view.View.dispatchPointerEvent(View.java:11009)
       at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5155)
       at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5007)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4532)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4585)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4551)
       at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4684)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4559)
       at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4741)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4532)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4585)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4551)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4559)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4532)
       at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7092)
       at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7024)
       at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6985)
       at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7202)
       at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:323)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Fatal Exception: java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/Instant;
       at kotlinx.datetime.Instant.<clinit>(Instant.kt:96)
       at kotlinx.datetime.Clock$System.now(Clock.kt:25)
       at com.chrynan.navigation.NavigationEvent$Forward$Destination.<init>(NavigationEvent.kt:105)
       at com.chrynan.navigation.NavigatorKt.goTo(Navigator.kt:107)
       at com.wakaztahir.mindnode.ui.components.main.MainScreenKt$MainScreen$1$1$1$2.invoke(MainScreen.kt:116)
       at com.wakaztahir.mindnode.ui.components.main.MainScreenKt$MainScreen$1$1$1$2.invoke(MainScreen.kt:102)
       at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke-k-4lQ0M(Clickable.kt:167)
       at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke(Clickable.kt:156)
       at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1.invokeSuspend(TapGestureDetector.kt:255)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:177)
       at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
       at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:368)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:566)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:456)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:469)
       at androidx.compose.ui.node.BackwardsCompatNode.onPointerEvent-H0pRuoY(BackwardsCompatNode.kt:374)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:314)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:183)
       at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:102)
       at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:98)
       at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1361)
       at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1307)
       at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1246)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2864)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2549)
       at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:609)
       at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1895)
       at android.app.Activity.dispatchTouchEvent(Activity.java:3241)
       at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:571)
       at android.view.View.dispatchPointerEvent(View.java:11009)
       at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5155)
       at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5007)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4532)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4585)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4551)
       at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4684)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4559)
       at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4741)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4532)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4585)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4551)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4559)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4532)
       at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7092)
       at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7024)
       at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6985)
       at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7202)
       at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:323)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
@chRyNaN
Copy link
Owner

chRyNaN commented May 30, 2023

expect/actual would not solve this problem. You should be able to add the kotlinx.datetime dependency to your project and may also need to use Android desugaring which allows usage of the java.time components in Android (which is what kotlinx.datetime's actual implementation uses on Android and JVM).

https://developer.android.com/studio/write/java8-support-table

@wakaztahir
Copy link
Author

I've done it for the time being as I don't want latest version to crash on devices But since this is a navigation library I expected it to not rely on kotlinx datetime and work without desugaring I think that'd be a plus +1

@chRyNaN
Copy link
Owner

chRyNaN commented May 30, 2023

I will look into including the Android Desugaring process in the library's build file for a future release.

@wakaztahir
Copy link
Author

Why is using kotlin date time important...?

@chRyNaN
Copy link
Owner

chRyNaN commented May 31, 2023

The navigation events are timestamped:

  • This allows each event, even subsequent ones of the same type, to be emitted since they are considered different. (StateFlows by nature perform similarly to the distinctUntilChanged operator in that they do not emit the same value twice in a row). The timestamp makes sure that all events are accessed, for instance, two goBack calls will actually go back twice.
  • In a future release, replay/time-travel features can be introduced which will help with debugging. This requires some concept of time tracking of the events.
  • Whatever model is used for storing time for an event must be serializable with kotlinx serialization as that is used to store and restore the state of a Navigator between configuration changes within the app via the rememberSavableNavigator calls.
  • The kotlinx datetime library already provides an abstraction layer (expect/actual) of the Instant type. No need to duplicate this abstraction.

It is possible that I can change the timestamp value from an Instant to perhaps a local clock value. This would remove the dependency on kotlinx.datetime but might produce issues if for whatever reason the local clock restarts or comes out of sync. This will also prevent restoring to a previous Navigator state using serialization as the local clock times will be different (other than for short ranges as it is used now, such as between processes in a Bundle), though that is out of scope anyway.

@chRyNaN
Copy link
Owner

chRyNaN commented Jul 12, 2023

This is addressed by the following PR and will the fix will be out in the next release: #10

@chRyNaN chRyNaN closed this as completed Jul 12, 2023
chRyNaN added a commit that referenced this issue Jul 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants