最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

kotlin - Stripe processing 3ds payment on Android - Stack Overflow

programmeradmin9浏览0评论

I have the following problem, processing payment with 3ds card. My app uses Jetpack compose I have a payment screen. So I create a payment intent with new or saved card. Then I check if I need 3ds and start 3ds processing the following way:

@Composable
fun ThreeDSScreen(
    publishableKey: String,
    secret: String,
    onSuccess: () -> Unit,
    onCancel: () -> Unit,
    onFail: () -> Unit
) {
    val paymentLauncher = rememberPaymentLauncher(
        publishableKey = publishableKey,
        stripeAccountId = null,
        callback = PaymentResultCallback(
            onSuccess = onSuccess,
            onCancel = onCancel,
            onFail = onFail
        )
    )
    val needLaunch = remember { mutableStateOf(true) }

    LaunchedEffect(secret) {
        if (needLaunch.value) {
            needLaunch.value = false
            delay(200)
            paymentLauncher.confirm(
                ConfirmPaymentIntentParams.create(
                    clientSecret = secret,
                    paymentMethodType = PaymentMethod.Type.CardPresent
                )
            )
        }
    }
}

class PaymentResultCallback(
    private val onSuccess: () -> Unit,
    private val onCancel: () -> Unit,
    private val onFail: () -> Unit
) : PaymentLauncher.PaymentResultCallback {
    override fun onPaymentResult(paymentResult: PaymentResult) {
        when (paymentResult) {
            is PaymentResult.Completed -> { onSuccess() }
            is PaymentResult.Canceled -> { onCancel() }
            is PaymentResult.Failed -> { onFail() }
        }
    }
}

I also save client secret in encrypted shared prefs. And it works fine whether a user fails it or cancel or confirm it. But let's imagine I stopped app. And I want in my app on start to check if pending intent exists. So I check it. And if I see a pending intent I try to confirm it the same way. Passing client secret to this composable. I use Stripe test VISA card with 3ds in order to check. So I start this function and see the Stripe 3ds test screen is starting and just after that Stripe behaves as if a user pressed fail. What am I doing wrong? I checked that my secret key is ok.

UPD: After running Stripe confirm I get Fail. So I'm trying to cancel pending payment intent. If I didn't succeed, I try to confirm again and from the second time it runs successfully. It seems that there's some problem with running this confirmation.

I have the following problem, processing payment with 3ds card. My app uses Jetpack compose I have a payment screen. So I create a payment intent with new or saved card. Then I check if I need 3ds and start 3ds processing the following way:

@Composable
fun ThreeDSScreen(
    publishableKey: String,
    secret: String,
    onSuccess: () -> Unit,
    onCancel: () -> Unit,
    onFail: () -> Unit
) {
    val paymentLauncher = rememberPaymentLauncher(
        publishableKey = publishableKey,
        stripeAccountId = null,
        callback = PaymentResultCallback(
            onSuccess = onSuccess,
            onCancel = onCancel,
            onFail = onFail
        )
    )
    val needLaunch = remember { mutableStateOf(true) }

    LaunchedEffect(secret) {
        if (needLaunch.value) {
            needLaunch.value = false
            delay(200)
            paymentLauncher.confirm(
                ConfirmPaymentIntentParams.create(
                    clientSecret = secret,
                    paymentMethodType = PaymentMethod.Type.CardPresent
                )
            )
        }
    }
}

class PaymentResultCallback(
    private val onSuccess: () -> Unit,
    private val onCancel: () -> Unit,
    private val onFail: () -> Unit
) : PaymentLauncher.PaymentResultCallback {
    override fun onPaymentResult(paymentResult: PaymentResult) {
        when (paymentResult) {
            is PaymentResult.Completed -> { onSuccess() }
            is PaymentResult.Canceled -> { onCancel() }
            is PaymentResult.Failed -> { onFail() }
        }
    }
}

I also save client secret in encrypted shared prefs. And it works fine whether a user fails it or cancel or confirm it. But let's imagine I stopped app. And I want in my app on start to check if pending intent exists. So I check it. And if I see a pending intent I try to confirm it the same way. Passing client secret to this composable. I use Stripe test VISA card with 3ds in order to check. So I start this function and see the Stripe 3ds test screen is starting and just after that Stripe behaves as if a user pressed fail. What am I doing wrong? I checked that my secret key is ok.

UPD: After running Stripe confirm I get Fail. So I'm trying to cancel pending payment intent. If I didn't succeed, I try to confirm again and from the second time it runs successfully. It seems that there's some problem with running this confirmation.

Share Improve this question edited Nov 18, 2024 at 23:04 Al Sh asked Nov 18, 2024 at 15:42 Al ShAl Sh 511 silver badge4 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0

It sounds like you're running into an issue where the 3D Secure (3DS) flow is prematurely failing when you try to confirm the payment intent after the app is restarted, even though the clientSecret and setup seem correct. The issue could be related to how the payment confirmation process is triggered after the app restarts, as well as how the payment state is handled in your app during the reinitialization.

Here's the code : first pic of the code : [1]: https://i.sstatic/nzkDItPN.png

It appears you are mistakenly indicating CardPresent (which is for use with Stripe Terminal and reading cards in person), instead of Card for online cards.

I would recommend you revise this line and retest everything:

 - paymentMethodType = PaymentMethod.Type.CardPresent
 + paymentMethodType = PaymentMethod.Type.Card
发布评论

评论列表(0)

  1. 暂无评论