stripe / stripe-android

Stripe Android SDK
https://stripe.com/docs/mobile/android
MIT License
1.3k stars 651 forks source link

[BUG] CardInputWidget does not restore state properly with Compose #7788

Closed dabluck closed 5 months ago

dabluck commented 10 months ago

Summary

When #onRestoreState runs, the CardInputWidget breaks and nothing can be entered. Specifically I believe the internal cardNumberTextInputLayout has a width of 0 and therefore nothing can be entered. This is happening with jetpack compose although I'm not sure state restoration would be different without compose

Code to reproduce

Sample Repo Specific Code

Android version

Observed on Android 12 and Android 14 emulators but seems to be universal

Installation method

Gradle

Dependency Versions

kotlin: 1.9.0 stripe-android: 20.36.1 Android Gradle Plugin: 8.2.1 Gradle: 8.2

SDK classes

CardInputWidget

Video

stripe.webm

tillh-stripe commented 10 months ago

Hi @dabluck 👋 Thanks for reporting this and double-thanks for providing a sample for reproducing the issue 🙏

We’ll have a look into that issue and let you know what we find.

gabrielbmoro commented 9 months ago

Just adding I am passing for the same issue. After a navigation event in a Compose application, backing to the screen where I have placed the CardInputWidget, this component is frozen. It looks like for some reason the state is not restored. Is there any update about the progress of this issue? Thanks in advance!

jaynewstrom-stripe commented 9 months ago

Internal ref: https://jira.corp.stripe.com/browse/RUN_MOBILESDK-2878

You can avoid this state restoration issue by creating the CardInputWidget once (for example outside of compose), and passing it into the widget like so.

@Composable
private fun StripeWidget(
    stateHolder: SaveableStateHolder,
    cardInputWidget: CardInputWidget,
) {
    stateHolder.SaveableStateProvider("stripe_elements") {
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp)
        ) {
            Box {
                AndroidView(
                    modifier = Modifier
                        .fillMaxWidth(),
                    factory = {
                        cardInputWidget
                    },
                    update = {
                        // do nothing
                    },
                    onRelease = {
                    },
                )
            }
        }
    }
}
jaynewstrom-stripe commented 9 months ago

Please reopen if you still have issues.

dabluck commented 9 months ago

@jaynewstrom-stripe That is a workaround for some cases but it's not a solution. The state restoration is broken. If for example the activity was torn down and recreated, creating it once is not possible.

upside-sarah commented 7 months ago

+1 to @dabluck's comment, unfortunately the suggested workaround isn't a viable long-term solution. Would really appreciate a fix for this, since it makes the widget unusable for our users 🙏

gabrielbmoro commented 7 months ago

@jaynewstrom-stripe , I tried the workaround you said, it did not work for me 😢

Do you have any other suggestion?

Ty in advance 🙏🏼

jaynewstrom-stripe commented 5 months ago

This was fixed in https://github.com/stripe/stripe-android/pull/8543 and is in the latest release.

upside-sarah commented 5 months ago

@jaynewstrom-stripe Amazing, confirming that fix worked for us! Thanks for following up!

gabrielbmoro commented 5 months ago

Thank you so much for all the work to solve this issue 😀