stripe / stripe-android

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

[BUG] Crash with No static method ModalBottomSheetLayout from 20.29.0 #7277

Closed Hospes closed 10 months ago

Hospes commented 10 months ago

Summary

Crash happen when I'm trying to initiate payment process with PaymentSheet with SDK versions 20.29.0 - 20.29.2, on version 20.28.3 it's working just fine.

Code to reproduce

Just open PaymentSheetActivity

Android version

Android 13

Impacted devices

OnePlus 10 Pro

Installation method

gradle dependency

Dependency Versions

kotlin: 1.9.10 stripe-android: 20.29.0 - 20.29.2 Android Gradle Plugin: 8.1.1 Gradle: 8.3

SDK classes

PaymentSheetActivity, BottomSheet, ModalBottomSheetLayout

Other information

java.lang.NoSuchMethodError: No static method ModalBottomSheetLayout-BzaUkTc(Lkotlin/jvm/functions/Function3;Landroidx/compose/ui/Modifier;Landroidx/compose/material/ModalBottomSheetState;Landroidx/compose/ui/graphics/Shape;FJJJLkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V in class Landroidx/compose/material/ModalBottomSheetKt; or its super classes (declaration of 'androidx.compose.material.ModalBottomSheetKt' appears in /data/app/~~IjAb55klwyFThiBxQd3tMQ==/com.whoppah.qa-LSzsidYOUkv6y7sXKHg8sQ==/base.apk)
at com.stripe.android.common.ui.BottomSheetKt.BottomSheet(BottomSheet.kt:166)
at com.stripe.android.paymentsheet.PaymentSheetActivity$onCreate$2$1.invoke(PaymentSheetActivity.kt:77)
at com.stripe.android.paymentsheet.PaymentSheetActivity$onCreate$2$1.invoke(PaymentSheetActivity.kt:62)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:108)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.material.MaterialTheme_androidKt.PlatformMaterialTheme(MaterialTheme.android.kt:23)
at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:82)
at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:81)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:108)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material.TextKt.ProvideTextStyle(Text.kt:396)
at androidx.compose.material.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:81)
at androidx.compose.material.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:80)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:108)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material.MaterialThemeKt.MaterialTheme(MaterialTheme.kt:72)
at com.stripe.android.uicore.StripeThemeKt$StripeTheme$1.invoke(StripeTheme.kt:331)
at com.stripe.android.uicore.StripeThemeKt$StripeTheme$1.invoke(StripeTheme.kt:330)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:108)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at com.stripe.android.uicore.StripeThemeKt.StripeTheme(StripeTheme.kt:325)
at com.stripe.android.paymentsheet.PaymentSheetActivity$onCreate$2.invoke(PaymentSheetActivity.kt:62)
at com.stripe.android.paymentsheet.PaymentSheetActivity$onCreate$2.invoke(PaymentSheetActivity.kt:61)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:108)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.ui.platform.ComposeView.Content(ComposeView.android.kt:428)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:252)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:251)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:108)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:195)
... tell me if you need full stacktrace
jameswoo-stripe commented 10 months ago

Hi @Hospes what compose version are you running?

Hospes commented 10 months ago

@jameswoo-stripe android compose 1.5.1

jameswoo-stripe commented 10 months ago

Thanks for the quick response. Could you also provide a small code snippet showcasing how you are launching PaymentSheet?

I just tested with this simple app to launch PaymentSheet, but not seeing the crash you are getting:

https://gist.github.com/jameswoo-stripe/d68d55a3fa3f644323151ba8f1f61e82

Hospes commented 10 months ago
@Composable
private fun CheckoutScreen(
    viewModel: CheckoutViewModel,
    navigateUp: () -> Unit,
    navigateChatThread: (String?) -> Unit,
) {
    val ctx = LocalContext.current
    val stripePublishKey = remember { PaymentConfiguration.getInstance(ctx).publishableKey }
    val stripe = remember(stripePublishKey) { Stripe(ctx, stripePublishKey) }

    val navController = rememberNavController()
    val paymentSheet = rememberPaymentSheet {
        viewModel.submitAction(CheckoutViewAction.PaymentResult(it))
    }

    val needAddress = rememberLauncherForActivityResult(EditAddressResultContract) {
        val address = if (it is EditAddressResultContract.EditResult.Ok) it.address else return@rememberLauncherForActivityResult
        viewModel.submitAction(CheckoutViewAction.SelectAddress(address))
        viewModel.submitAction(CheckoutViewAction.NavigateNextStep)
    }

    LaunchedEffect(viewModel.events) {
        viewModel.events.collect { event ->
            when (event) {
                is CheckoutViewEvent.StartPaymentFlow -> {
                    paymentSheet.presentWithPaymentIntent(paymentIntentClientSecret = event.clientSecret)
                }
                ...
                is CheckoutViewEvent.AddressNeeded -> needAddress.launch(null)
            }
        }
    }
}
jameswoo-stripe commented 10 months ago

Thanks for the example, I will try to recreate this scenario.

Hospes commented 10 months ago

THis really strange, because what I'm doing is just only updating to latest version of the stripe and I got this crash...

jameswoo-stripe commented 10 months ago

@Hospes Have you tried other devices? Like Pixel, Samsung, etc...

Hospes commented 10 months ago

I don't have different, but emulator crashes also

jameswoo-stripe commented 10 months ago

Can you provide your build.gradle, there might be a compose compatibility issue

Hospes commented 10 months ago

Well my application is heavy moduled, I can show you how dependencies applied:

dependencies {
    implementation(project(":core:base"))
    implementation(project(":domain"))
    implementation(project(":common:ui:compose"))
    implementation(project(":common:ui:compose-icons"))
    implementation(project(":common:ui:view"))

    implementation(project(":ui:about"))
    implementation(project(":ui:faq"))
    implementation(project(":ui:main:home"))
    implementation(project(":ui:main:favorites"))
    implementation(project(":ui:main:account"))
    implementation(project(":ui:address:edit"))
    implementation(project(":ui:product:create"))
    implementation(project(":ui:product:create-tips"))
    implementation(project(":ui:product:details"))
    implementation(project(":ui:product:common"))
    implementation(project(":ui:auth:forgot"))
    implementation(project(":ui:auth:boarding"))
    implementation(project(":ui:auth:signin"))
    implementation(project(":ui:auth:signup"))
    implementation(project(":ui:search:main"))
    implementation(project(":ui:gallery"))
    implementation(project(":ui:collection"))
    implementation(project(":ui:report"))
    implementation(project(":ui:page"))
    implementation(project(":ui:hww"))

    implementation(libs.kotlinx.serialization.json)

    // Compose
    //implementation platform(libs.androidx.compose.bom)              // Official bom lib with compose stable version
    //implementation platform(libs.androidx.compose.bom.chrisbanes)   // Use ChrisBanes bom lib for compose alpha version
    implementation(libs.bundles.androidx.compose)

    implementation(libs.bundles.accompanist)

    implementation(libs.compose.destinations.core)
    ksp(libs.compose.destinations.ksp)

    implementation(libs.bundles.lifecycle)

    implementation(libs.androidx.navigation)

    implementation(libs.androidx.core)
    implementation(libs.androidx.activity.compose)
    implementation(libs.androidx.fragment)
    implementation(libs.androidx.constraintlayout)
    implementation(libs.androidx.recyclerview)
    implementation(libs.androidx.preference)
    implementation(libs.google.material)

    implementation(libs.google.hilt.android)
    ksp(libs.google.hilt.compiler)
    implementation(libs.androidx.hilt.navigation)

    implementation(libs.google.play.app.update)
    implementation(libs.google.auth)

    // Import the BoM for the Firebase platform
    implementation(platform(libs.firebase.bom))
    implementation(libs.bundles.firebase)

    implementation(libs.easyImage)
    implementation(libs.progressbutton)
    implementation(libs.libphonenumber.android)
    implementation(libs.viewbindingpropertydelegate)

    implementation(libs.facebook.login)
    implementation(libs.bundles.braze)
    implementation(libs.bundles.coil)

    implementation(libs.stripe)
    implementation(libs.timber)
}

With this bundle implementation(libs.bundles.androidx.compose) applied these dependencies:

androidx-compose = [
    "androidx-compose-ui", "androidx-compose-ui-util", "androidx-compose-ui-tooling",
    "androidx-compose-foundation", "androidx-compose-foundation-layout",
    "androidx-compose-runtime", "androidx-compose-animation",
    "androidx-compose-material", "androidx-compose-material-icons-extended"
]

Also i'm not using bom, so for all compose dependencies I'm aplying the same version 1.5.1

Hospes commented 10 months ago

@jameswoo-stripe by the way, in github gists that you posted above, there is used android compose bom 2022.10.00, it's outdated a lot. Try to use compose 1.5.1 please.

Hospes commented 10 months ago

Well I've tried clean/new project So it's almost identical to yours gists. https://gist.github.com/Hospes/7c7433450b276218bbbeae10c560041b The main differences is: kotlin 1.9.10 compose bom 2023.09.00 material instead of material3

And it's crashing with the same issue.

fbarthelery commented 10 months ago

I've had this issue for a while. It occurs when your app is using compose 1.5.x. The ABI for ModalBottomSheetLayout changed in 1.5.x.

There a few more issues that are caused when using latest compose version. This should all be fixed when the stripe update to compose 1.5.0-1.5.1

jameswoo-stripe commented 10 months ago

FYI, we are planning to update the SDK to use 1.5.1, here is the PR