Closed reiaz-gafar closed 2 years ago
Hi @reiaz-gafar, thank you for reporting this issue. Can you provide a little more information:
confirmParams
looks like? For example, which payment method you are usingpaymentLauncher
Hi @jameswoo-stripe.
ConfirmPaymentIntentParams(paymentMethodCreateParams=PaymentMethodCreateParams(type=card, card=Card(number=4242424242424242, expiryMonth=2, expiryYear=2042, cvc=424, token=null, attribution=[CardInputView]), ideal=null, fpx=null, sepaDebit=null, auBecsDebit=null, bacsDebit=null, sofort=null, upi=null, netbanking=null, billingDetails=BillingDetails(address=Address(city=null, country=null, line1=null, line2=null, postalCode=, state=null), email=null, name=null, phone=null), metadata=null, productUsage=[], overrideParamMap=null), paymentMethodId=null, sourceParams=null, sourceId=null, clientSecret=pi_xxxxxxxxxxxxxxxxxx_secret_xxxxxxxxxxxxxxxxxx, returnUrl=null, savePaymentMethod=null, useStripeSdk=false, paymentMethodOptions=null, mandateId=null, mandateData=null, setupFutureUsage=null, shipping=null, receiptEmail=null)
(I x'd out the client secret after I pasted here)
Payment launcher is constructed using a fragment like so: PaymentLauncher.Companion.create(fragment, publishableKey, stripeAccountId, callback)
@reiaz-gafar, thanks for the information. Been trying to reproduce this issue without any success, it is hard to find out why the coroutine is cancelling without more information.
I can propose a bandaid solution that will just wrap the JobCancellationException
into a Throwable
, so that when we try to serialize it, it won't crash.
In the meantime, it would be helpful to understand how you are using PaymentLauncher
. Anything will help, even pseudocode to help debug the issue, please be as specific as you can. Questions off the top of my head:
PaymentLauncher
paymentLauncher.confirm(confirmParams)
PaymentLauncher
created before fragment is created (can be a lateinit var
) > create payment intent > when the payment intent is created get the client secret > use PaymentLauncher
to confirm payment > callback should be called with some PaymentResult
Thanks for looking into this @jameswoo-stripe. I've created a stripped down sample app where I'm still seeing the issue here: https://github.com/reiaz-gafar/stripe-manual-entry-crash.
It still has the same crash location
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.stripemanualentrysampleapp, PID: 3259
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = kotlinx.coroutines.JobCancellationException)
As for our main app where it's crashing to answer your questions:
PaymentLauncher
is being created in the onCreate
of the fragment. The launcher itself is being held as a property of the fragment's view model so it's created like so fragmentViewModel.createPaymentLauncher(this)
. We pass in a reference to the fragment so the view model has the information it needs to create the launcher. This is the function and property in the view model. stripeManualEntry
is a service that wraps the SDK calls. private var paymentLauncher: PaymentLauncher? = null
fun createPaymentLauncher(fragment: Fragment) {
paymentLauncher = stripeManualEntry.createPaymentLauncher(fragment, ::onPaymentResult)
}
We end up calling paymentLauncher.confirm
when the user taps the pay button which we then grab the information from the card widget like so:
cardInputWidget.paymentMethodCreateParams?.let { paymentMethodCreateParams ->
applicationScope().launch {
stripeManualEntry.confirmPayment(paymentMethodCreateParams, paymentIntentService.clientSecret.get(), paymentLauncher!!)
}
}
I can't see anything that would cause a cancellation on our end. We're expecting the callback from the payment launcher that we passed in here createPaymentLauncher(fragment, ::onPaymentResult)
but the app crashes before we enter the onPaymentResult
function. I'm pretty sure that we're following those suggested steps that you listed.
There may also be a reason to believe that Locale has something to do with this, is there something in the SDK that uses the locale to construct anything in this flow?
The reason I'm mentioning this is that we have a colleague in the UK that has the exact same code and does NOT crash, but myself and others in the New York City region ARE crashing.
Hi @reiaz-gafar thanks so much for the sample app. I tried it out and was not able to reproduce the issue. I am based in the Seattle region and I am not able to get a crash. I tested multiple emulators, upgraded my kotlin version, but no luck so far.
My machine:
Android emulator:
Here are some questions I have:
@jameswoo-stripe Thanks for continuing to look at this.
To answer your questions:
Running macOS Monterey 12.0
MacBook Pro 16 inch, 2021
M1 Pro Apple Silicon chip
No VPN being used
The request does not time out - it actually successfully confirms the payment intent, verfied on the dashboard, but it crashes before we hit the callback.
Here's a video of the crash that I'm seeing in the sample app I posted earlier:
@reiaz-gafar Thank you so much for the detailed responses! This was extremely valuable information and we have found the issue. This issue seems to happen on landscape mode and not portrait mode. There is a configuration change which causes the JobCancellationException
being thrown. We will take a look into getting a fix out, thanks again!
@jameswoo-stripe Awesome, that's great to hear! Thanks so much for taking the time to look into this.
Any tentative idea on how long it will take to release?
@reiaz-gafar You can subscribe to this PR: https://github.com/stripe/stripe-android/pull/4776. Once merged we can discuss about releasing a patch fix. In the meantime, can you work on this using portrait mode (e.g. using a phone instead of a tablet)?
@jameswoo-stripe Thanks for raising that PR, I have suscribed. Unfortunately our app is locked to landscape mode so we are blocked until this patch is released. Thanks again for looking into this and communicating well!
Hi @reiaz-gafar, the fix is merged and we are scheduling a release for April 4. Once released, feel free to update your dependency. Please let us know if you run into more issues.
@jameswoo-stripe Amazing, thanks so much for the quick resolution!
@jameswoo-stripe Tried out the new release. Unfortunately I'm still getting a crash, not the same one as before though.
2022-04-05 11:07:51.317 3990-4536/? E/Parcel: Class not found when unmarshalling: com.stripe.android.payments.paymentlauncher.PaymentLauncherContract$Args$IntentConfirmationArgs
java.lang.ClassNotFoundException: com.stripe.android.payments.paymentlauncher.PaymentLauncherContract$Args$IntentConfirmationArgs
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:454)
at android.os.Parcel.readParcelableCreator(Parcel.java:3031)
at android.os.Parcel.readParcelable(Parcel.java:2981)
at android.os.Parcel.readValue(Parcel.java:2883)
at android.os.Parcel.readArrayMapInternal(Parcel.java:3261)
at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
at android.os.BaseBundle.unparcel(BaseBundle.java:236)
at android.os.BaseBundle.getString(BaseBundle.java:1160)
at android.content.Intent.getStringExtra(Intent.java:8548)
at com.android.server.wm.ActivityStarter.startActivity(ActivityStarter.java:790)
at com.android.server.wm.ActivityStarter.startActivity(ActivityStarter.java:694)
at com.android.server.wm.ActivityStarter.startActivityMayWait(ActivityStarter.java:1932)
at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:625)
at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1707)
at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1603)
at com.android.server.wm.ActivityTaskManagerService.startActivity(ActivityTaskManagerService.java:1557)
at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1690)
at android.os.Binder.execTransactInternal(Binder.java:1056)
at android.os.Binder.execTransact(Binder.java:1029)
Caused by: java.lang.ClassNotFoundException: com.stripe.android.payments.paymentlauncher.PaymentLauncherContract$Args$IntentConfirmationArgs
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:454)
at android.os.Parcel.readParcelableCreator(Parcel.java:3031)
at android.os.Parcel.readParcelable(Parcel.java:2981)
at android.os.Parcel.readValue(Parcel.java:2883)
at android.os.Parcel.readArrayMapInternal(Parcel.java:3261)
at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
at android.os.BaseBundle.unparcel(BaseBundle.java:236)
at android.os.BaseBundle.getString(BaseBundle.java:1160)
at android.content.Intent.getStringExtra(Intent.java:8548)
at com.android.server.wm.ActivityStarter.startActivity(ActivityStarter.java:790)
at com.android.server.wm.ActivityStarter.startActivity(ActivityStarter.java:694)
at com.android.server.wm.ActivityStarter.startActivityMayWait(ActivityStarter.java:1932)
at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:625)
at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1707)
at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1603)
at com.android.server.wm.ActivityTaskManagerService.startActivity(ActivityTaskManagerService.java:1557)
at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1690)
at android.os.Binder.execTransactInternal(Binder.java:1056)
at android.os.Binder.execTransact(Binder.java:1029)
The payment is still succesfully confirmed on the dashboard as well.
I tried the same exact app in portrait mode and it works fine. Any ideas on why it's still happening?
@reiaz-gafar I have tried reproducing the issue you are seeing with a tablet in landscape mode in both our example app and the app that you posted previously. Unfortunately, I am unable to see the issue you are seeing. Have you tried invalidating and restarting Android Studio, clearing the gradle cache, cleaning and rebuilding?
20.0.0 does include some breaking changes, but I can't see anything that would have changed with IntentConfirmationArgs
. See the migration guide, just in case.
@jameswoo-stripe Let me do a bit more investigation and get back, it can totally be something on our side.
Hi @jameswoo-stripe, I see below code in PaymentLauncherConfirmationActivity.kt which changes activity orientation to portrait mode. This might explain why we have this issue.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O) {
// In Oreo, Activities where `android:windowIsTranslucent=true` can't request
// orientation. See https://stackoverflow.com/a/50832408/11103900
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
Hi @jameswoo-stripe I tried the latest SDK in portrait and it does crash the application for me too. However, if I run it on an emulator that is specifically SDK 26 (Android Oreo), it works fine. That would indicate to me that it is this line that is causing the crash.
What would be the ramifications if you were to just remove the orientation line completely?
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
Hi @jameswoo-stripe, my teammates posted some of their findings above, what do you think of them?
@anandkumarnyc, @keithmacklin, @reiaz-gafar, thanks for the follow up. I am consulting with the team to see if we can remove the force portrait mode.
@anandkumarnyc @keithmacklin @reiaz-gafar here is a potential workaround PR up: https://github.com/stripe/stripe-android/pull/4855
@anandkumarnyc @keithmacklin @reiaz-gafar hi folks, https://github.com/stripe/stripe-android/pull/4855 was merged. Please be on the lookout for a release this Monday.
@reiaz-gafar Please update to 20.1.0 and let us know if this fixes your issue.
@jameswoo-stripe It's looking pretty good now, thanks! Going to do a bit more testing but everything seems to be in order 🤞
Great, thank you for the update! Feel free to open a new issue if you find one.
Summary
When trying to use the PaymentLauncher to confirm a payment, it crashes the app.
Code to reproduce
paymentLauncher.confirm(confirmParams)
Android version
Using Android 12, happening on Stripe SDK versions 17+
Impacted devices
Happens on all devices tried on.
Installation method
Gradle
Dependency Versions
kotlin: 1.6.10 stripe-android: 19.3.0 Android Gradle Plugin: 7.1.2 Gradle: 7.3.3
SDK classes
PaymentLauncher
Video
Other information
The payment intent in Stripe dashboard indicates that the payment intent was successfully confirmed, but we crash before we receive the callback.
Stack trace: