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

Fatal Exception: java.lang.IllegalStateException - com.google.android.gms.dynamite.DynamiteModule$LoadingException: Remote load failed. No local fallback found. #109

Closed
mohsenoid opened this issue Dec 11, 2024 · 6 comments

Comments

@mohsenoid
Copy link
Contributor

mohsenoid commented Dec 11, 2024

We are using this library v1.0.0 to show the GooglePay button, but during GmsPayButton initialization this exception happens and we cannot catch it in the compose UI.

Fatal Exception: java.lang.IllegalStateException
com.google.android.gms.dynamite.DynamiteModule$LoadingException: Remote load failed. No local fallback found.

Device: OnePlus 11 5G
OS version: android 14

Here is the full stack trace:

Fatal Exception: java.lang.IllegalStateException
com.google.android.gms.dynamite.DynamiteModule$LoadingException: Remote load failed. No local fallback found.

com.google.android.gms.wallet.button.zzf.zzb (com.google.android.gms:play-services-wallet@@19.3.0:2)
com.google.android.gms.wallet.button.zzf.zza (com.google.android.gms:play-services-wallet@@19.3.0:1)
com.google.android.gms.wallet.button.PayButton.initialize (com.google.android.gms:play-services-wallet@@19.3.0:17)
com.google.pay.button.PayButtonKt$PayButton$1$1.invoke (PayButton.kt:66)
com.google.pay.button.PayButtonKt$PayButton$1$1.invoke (PayButton.kt:64)
androidx.compose.ui.viewinterop.ViewFactoryHolder.<init> (AndroidView.android.kt:344)
androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1$1.invoke (AndroidView.android.kt:275)
androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1$1.invoke (AndroidView.android.kt:274)
androidx.compose.runtime.changelist.Operation$InsertNodeFixup.execute (Operation.kt:583)
androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations (Operations.kt:309)
androidx.compose.runtime.changelist.FixupList.executeAndFlushAllPendingFixups (FixupList.kt:50)
androidx.compose.runtime.changelist.Operation$InsertSlotsWithFixups.execute (Operation.kt:550)
androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations (Operations.kt:309)
androidx.compose.runtime.changelist.ChangeList.executeAndFlushAllPendingChanges (ChangeList.kt:81)
androidx.compose.runtime.CompositionImpl.applyChangesInLocked (Composition.kt:984)
androidx.compose.runtime.CompositionImpl.applyChanges (Composition.kt:1013)
androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke (Recomposer.kt:685)
androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke (Recomposer.kt:585)
androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame (AndroidUiFrameClock.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch (AndroidUiDispatcher.android.kt:109)
androidx.compose.ui.platform.AndroidUiDispatcher.access$setScheduledFrameDispatch$p (AndroidUiDispatcher.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch (AndroidUiDispatcher.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame (AndroidUiDispatcher.android.kt:69)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1523)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1534)
android.view.Choreographer.doCallbacks (Choreographer.java:1089)
android.view.Choreographer.doFrame (Choreographer.java:975)
android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1508)
android.os.Handler.handleCallback (Handler.java:958)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loopOnce (Looper.java:255)
android.os.Looper.loop (Looper.java:364)
android.app.ActivityThread.main (ActivityThread.java:8979)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:572)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1053)

Caused by com.google.android.gms.dynamite.DynamiteModule$LoadingException
Remote load failed. No local fallback found.

com.google.android.gms.dynamite.DynamiteModule.load (com.google.android.gms:play-services-basement@@18.3.0:62)
com.google.android.gms.wallet.button.zzf.zzb (com.google.android.gms:play-services-wallet@@19.3.0:1)
com.google.android.gms.wallet.button.zzf.zza (com.google.android.gms:play-services-wallet@@19.3.0:1)
com.google.android.gms.wallet.button.PayButton.initialize (com.google.android.gms:play-services-wallet@@19.3.0:17)
com.google.pay.button.PayButtonKt$PayButton$1$1.invoke (PayButton.kt:66)
com.google.pay.button.PayButtonKt$PayButton$1$1.invoke (PayButton.kt:64)
androidx.compose.ui.viewinterop.ViewFactoryHolder.<init> (AndroidView.android.kt:344)
androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1$1.invoke (AndroidView.android.kt:275)
androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1$1.invoke (AndroidView.android.kt:274)
androidx.compose.runtime.changelist.Operation$InsertNodeFixup.execute (Operation.kt:583)
androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations (Operations.kt:309)
androidx.compose.runtime.changelist.FixupList.executeAndFlushAllPendingFixups (FixupList.kt:50)
androidx.compose.runtime.changelist.Operation$InsertSlotsWithFixups.execute (Operation.kt:550)
androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations (Operations.kt:309)
androidx.compose.runtime.changelist.ChangeList.executeAndFlushAllPendingChanges (ChangeList.kt:81)
androidx.compose.runtime.CompositionImpl.applyChangesInLocked (Composition.kt:984)
androidx.compose.runtime.CompositionImpl.applyChanges (Composition.kt:1013)
androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke (Recomposer.kt:685)
androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke (Recomposer.kt:585)
androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame (AndroidUiFrameClock.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch (AndroidUiDispatcher.android.kt:109)
androidx.compose.ui.platform.AndroidUiDispatcher.access$setScheduledFrameDispatch$p (AndroidUiDispatcher.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch (AndroidUiDispatcher.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame (AndroidUiDispatcher.android.kt:69)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1523)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1534)
android.view.Choreographer.doCallbacks (Choreographer.java:1089)
android.view.Choreographer.doFrame (Choreographer.java:975)
android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1508)
android.os.Handler.handleCallback (Handler.java:958)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loopOnce (Looper.java:255)
android.os.Looper.loop (Looper.java:364)
android.app.ActivityThread.main (ActivityThread.java:8979)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:572)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1053)
@dmengelt
Copy link
Member

@mohsenoid does your device have "Google Play Services" installed?

@mohsenoid
Copy link
Contributor Author

mohsenoid commented Dec 12, 2024

@mohsenoid does your device have "Google Play Services" installed?

It is a user device, which I believe it doesn't or has some old or broken Google Play Services version, but shouldn't the button somehow handle it?

What I did for the moment was copy the button source code and add a fallback UI solution just in case there was a crash in initialization till we get a proper fix for this thread:

@Composable
fun GooglePayButton(
    onClick: () -> Unit,
    allowedPaymentMethods: String,
    modifier: Modifier = Modifier,
    theme: GooglePayButtonTheme = GooglePayButtonTheme.Dark,
    type: GooglePayButtonType = GooglePayButtonType.Buy,
    radius: Dp = 100.dp,
    enabled: Boolean = true,
    onError: (Exception) -> Unit = {},
    fallbackUi: @Composable (() -> Unit)? = null,
) {

    var showFallback by remember { mutableStateOf(false) }

    val radiusPixelValue = with(LocalDensity.current) { radius.toPx().toInt() }

    if (!showFallback) {
        AndroidView(
            modifier = modifier,
            factory = { context ->
                val payButton = PayButton(context)

                try {
                    payButton.initialize(
                        ButtonOptions.newBuilder()
                            .setButtonTheme(theme.value)
                            .setButtonType(type.value)
                            .setCornerRadius(radiusPixelValue)
                            .setAllowedPaymentMethods(allowedPaymentMethods)
                            .build()
                    )
                } catch (e: Exception) {
                    onError(e)
                    showFallback = true
                }

                payButton
            },
            update = { button ->
                if (!showFallback) {
                    button.apply {
                        alpha = if (enabled) FULL_ALPHA else HALF_ALPHA
                        isEnabled = enabled

                        if (enabled) {
                            setOnClickListener { onClick() }
                        } else {
                            setOnClickListener(null)
                        }
                    }
                }
            }
        )
    } else {
        fallbackUi?.invoke()
    }
}

Such crashes where two worlds of View UI and Compose UI collide are hard to catch since we don't have try/catch in a compose function.

@dmengelt
Copy link
Member

dmengelt commented Dec 18, 2024

Thanks @mohsenoid
This is a very weird behaviour and an edge case I believe 😉

However, I can see we could improve our handling for those cases. I will look into this!

@dmengelt
Copy link
Member

@mohsenoid do you want to submit a PR with your fallback UI solution?

@mohsenoid
Copy link
Contributor Author

mohsenoid commented Dec 30, 2024

@mohsenoid do you want to submit a PR with your fallback UI solution?

Sure if you believe it is a decent and acceptable solution 👍

mohsenoid added a commit to mohsenoid/compose-pay-button that referenced this issue Dec 30, 2024
mohsenoid added a commit to mohsenoid/compose-pay-button that referenced this issue Dec 30, 2024
mohsenoid added a commit to mohsenoid/compose-pay-button that referenced this issue Dec 30, 2024
@mohsenoid
Copy link
Contributor Author

mohsenoid commented Dec 30, 2024

Done, open for review #113

dmengelt added a commit that referenced this issue Jan 6, 2025
…ptions

[#109] Handle potential init exceptions and fallback
@dmengelt dmengelt closed this as completed Jan 6, 2025
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

No branches or pull requests

2 participants