Adyen / adyen-android

Adyen Android Drop-in and Components
https://docs.adyen.com/checkout/android
MIT License
119 stars 66 forks source link

[v5.3.0] Using 3DS2 and Session when a transaction is `Refused`, the `SessionDropInCallback` is not called #1532

Closed gabrielglbh closed 1 month ago

gabrielglbh commented 1 month ago

Describe the bug When coming back from the bank verification using Session and DropIn, if the transaction somehow gets Refused, when coming back to the main app, the DropIn dismisses but the SessionDropInCallback is not called at all.

Only happens in Android 10. I have tried it in Android 14 and it goes smoothly as butter.

To Reproduce Steps to reproduce the behavior:

  1. Pay X amount of money with 3DS2 method
  2. Input the bank verification code in the activity
  3. The DropIn should vanish without the callback getting called

Expected behavior When coming back to the app from the bank verification page, I expect the flow to always go through SessionDropInCallback.

Screenshots

In Android 10 https://github.com/Adyen/adyen-android/assets/26835924/18f9491d-688e-463a-ab1c-b75d44682531

As you can see in the video, when returning back from the verification screen, the DropIn completely disappears and the SessionDropInCallback is not called (thus the appearance of the 2 or 3 other DropIns - expected). I know the code is Refused because when I dismiss the new DropIns, the failed one actually completes. Strange behaviour.

In Android 14 https://github.com/Adyen/adyen-android/assets/26835924/133a8e4f-0e43-4836-9a1b-1f24756c9fbc

Works fine and the callback gets executed and the expected error screen is shown.

Smartphone (please complete the following information):

araratthehero commented 1 month ago

Hi @gabrielglbh, thanks for opening the bug report.

I've followed the steps you provided but couldn't replicate the issue on an emulator and using SDK version 5.3.0.

To proceed further, could you please provide some additional information?

gabrielglbh commented 1 month ago

Hi @araratthehero of course!

I have tried the below code in different versions of Android SDK always with a Pixel 8 emulator device. Here are the Android versions in which the callback function works and does not work...

Here is the code to instantiate the drop-in with version 5.3.0 of Adyen:

var paymentSessionResponse: PaymentSessionResponse? = null
val dropInLauncher = rememberLauncherForDropInResult(callback = SessionDropInCallback {
    paymentSessionResponse = null
    // Finalize the session and check for the result code
    // Do some other stuff...
})

// When the session [PaymentSessionResponse] is created and not null, this LaunchedEffect will trigger
LaunchedEffect(paymentSessionResponse != null) {
    val configuration = CheckoutConfiguration(environment, ADYEN_CLIENT_KEY) {
        card {
            setHolderNameRequired(true)
        }
        dropIn {
            addCardConfiguration(this@CheckoutConfiguration.getCardConfiguration()!!)
            setAmount(...)
            setShowPreselectedStoredPaymentMethod(true)
        }
    }

    // PaymentSessionResponse is gathered previously to get the SessionID and SessionData as per the docs
    val result = runBlocking {
        return@runBlocking CheckoutSessionProvider.createSession(SessionModel(
            paymentSessionResponse.sessionId,
            paymentSessionResponse.sessionData
        ), configuration)
    }

    when (result) {
          is CheckoutSessionResult.Success -> {
              DropIn.startPayment(
                  context = context,
                  dropInLauncher = dropInLauncher,
                  checkoutSession = result.checkoutSession,
                  dropInConfiguration = configuration.getDropInConfiguration()!!
              )
          }

          is CheckoutSessionResult.Error -> { ... }
      }
}

Center(
    CustomButton(
        text = text,
        onClick = { 
            // Create the session for the drop-in, using mocks...
            paymentSessionResponse = PaymentSessionResponse("id", "data")
        }
    )
)

I do not have anymore clues on why is this failing, all the code related to the creation of the Drop-in is that. It seems that with my code below API 30 the callback does not work, it is rather strange...

Hope this comment helps debugging this :)

araratthehero commented 1 month ago

@gabrielglbh thanks for sharing the details.

I was still not able to reproduce the issue, but I have some ideas which can help:

I've also noticed that below API 30 the recomposition works differently in Compose.

Could you make the changes and let me know if it resolves the issue?

gabrielglbh commented 1 month ago

@araratthehero Thank you for the tips! I will try them next week and I will let you know ASAP!

gabrielglbh commented 1 month ago

@araratthehero It seemed that the trigger to the DropIn.startPayment was getting called various times even before the SessionDropInCallback was performed. Adding a control variable solved the issue. And I also applied the suggested change from the docs :) Thank you very much!

araratthehero commented 1 month ago

Hi @gabrielglbh, I am happy to hear it worked for you.