BreX900 / mek-packages

11 stars 14 forks source link

Cancelling collectPaymentMethod results in an unhandled error and a black screen #32

Closed payminty-shaun closed 11 months ago

payminty-shaun commented 11 months ago

I may be doing something wrong here but I am not sure how to handle cancelling the collectPaymentMethod screen that is shown.

Here is my log:

I/flutter (10941): Payment Status Changed: waitingForInput
W/ty.paymintyplus(10941): Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (unsupported, reflection, allowed)
W/ty.paymintyplus(10941): Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (unsupported, reflection, allowed)
I/StripeTerminal(10941): class=TerminalStatusManager message=endPaymentFlow.
D/StripeTerminal(10941): class=ProxyTerminalListener message=onPaymentStatusChange(READY)
E/StripeTerminal(10941): class=TerminalSession
E/StripeTerminal(10941): com.stripe.stripeterminal.external.models.TerminalException: Contactless transaction was canceled
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter.collectPaymentMethodHandler(CotsAdapter.kt:172)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter.collectPaymentMethod(CotsAdapter.kt:136)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.adapter.ProxyAdapter.collectPaymentMethod(ProxyAdapter.kt:144)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$CollectPaymentMethodOperation.executeIfNotCanceled(TerminalSession.kt:1297)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$CancelableOperation.execute(TerminalSession.kt:1058)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$ExternalOperation.run$terminalsession_release(TerminalSession.kt:1016)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession.enqueueOperation$lambda$6(TerminalSession.kt:875)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession.$r8$lambda$6lM7341_XI6PEqXfOM-yc2U5tkQ(Unknown Source:0)
E/StripeTerminal(10941):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$$ExternalSyntheticLambda0.run(Unknown Source:4)
E/StripeTerminal(10941):    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:487)
E/StripeTerminal(10941):    at java.util.concurrent.FutureTask.run(FutureTask.java:264)
E/StripeTerminal(10941):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
E/StripeTerminal(10941):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
E/StripeTerminal(10941):    at java.lang.Thread.run(Thread.java:1012)
I/flutter (10941): Payment Status Changed: ready

Advice on how to handle this would be great, thanks!

SimoneBressan commented 11 months ago

Are you trying the example app? The error should be handled What you see are just SDK logs You can disable them by putting shouldPrintLogs: false,

    final terminal = await Terminal.getInstance(
      shouldPrintLogs: false,
      fetchToken: _fetchConnectionToken,
    );
payminty-shaun commented 11 months ago

Sorry the issue isn't the error in the debug logs per se, but the black screen that is shown after the full screen prompt from the Stripe Terminal is cancelled.

I don't have this issue when a card is read and the full screen prompt closes successfully, just when the cancel button is pressed.

Here is a screen recording of what happens: Stripe Terminal Cancel Issue

What I expect to happen, is that I am returned to my app and am able to continue to interact as normal. Any advise would be great as I am new to Flutter and not sure if I am doing something wrong.

Thanks!

BreX900 commented 11 months ago

I don't think it's a problem with my plugin since I don't control the navigation and screens in any way, it could be a problem with the official stripe terminal sdk but I don't think so. You are probably doing one too many Navigator.pop(context) and therefore the navigation stack remains empty.

payminty-shaun commented 11 months ago

I'm not doing any Navigator.pop calls and am basically following the example code verbatim. I've implemented a WidgetsBindingObserver and the following code to monitor the app lifecycle state when the Stripe Terminal full screen prompt is shown. Here is the lifecycle code I implemented:

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
  super.didChangeAppLifecycleState(state);
  switch (state) {
    case AppLifecycleState.resumed:
      print("Lifecycle Change: App is in the foreground");
      break;
    case AppLifecycleState.inactive:
      print("Lifecycle Change: App is inactive");
      break;
    case AppLifecycleState.paused:
      print("Lifecycle Change: App is in the background but still running");
      break;
    case AppLifecycleState.detached:
      print("Lifecycle Change: App is in the process of being terminated");
      break;
    case AppLifecycleState.hidden:
      print("Lifecycle Change: App is not visible to the user");
      break;
  }
}

And here is the debug messages when the Stripe Terminal full screen prompt is shown and I tap the simulate button and am successfully returned to my app:

I/flutter (21115): Payment Intent retrieved.
I/flutter (21115): Payment Status Changed from PaymentStatus.ready to waitingForInput
D/CompatibilityChangeReporter(21115): Compat change id reported: 210923482; UID 10333; state: ENABLED
W/ty.paymintyplus(21115): Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (unsupported, reflection, allowed)
W/ty.paymintyplus(21115): Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (unsupported, reflection, allowed)
I/flutter (21115): Lifecycle Change: App is inactive //full screen terminal is displayed
I/flutter (21115): Lifecycle Change: App is not visible to the user
I/flutter (21115): Lifecycle Change: App is in the background but still running //full screen terminal successfully closes and starts to return to app.
I/flutter (21115): Lifecycle Change: App is not visible to the user
I/flutter (21115): Lifecycle Change: App is inactive 
I/flutter (21115): Lifecycle Change: App is in the foreground

for reference, here is what happens when the Stripe Terminal full screen widget is cancelled:

I/flutter (21798): Payment Intent retrieved.
D/CompatibilityChangeReporter(21798): Compat change id reported: 210923482; UID 10333; state: ENABLED
W/ty.paymintyplus(21798): Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (unsupported, reflection, allowed)
W/ty.paymintyplus(21798): Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (unsupported, reflection, allowed)
I/flutter (21798): Payment Status Changed from PaymentStatus.ready to waitingForInput
I/flutter (21798): Lifecycle Change: App is inactive
I/flutter (21798): Lifecycle Change: App is not visible to the user
I/flutter (21798): Lifecycle Change: App is in the background but still running //full screen terminal cancel button is pushed and app shows a black screen.
I/flutter (21798): Payment Status Changed from PaymentStatus.waitingForInput to ready 
I/flutter (21798): Payment Collection appears to be cancelled

Note that no further lifecycle messages are displayed once the cancel button is pressed and the black screen is shown (unlike the successful flow).

The Payment Status message is from the onPaymentStatusChangeSub - here is the code snippet so you can see what triggered the messages above:

_onPaymentStatusChangeSub =
        stripeTerminal.onPaymentStatusChange.listen((status) {
      print('Payment Status Changed from $_paymentStatus to ${status.name}');
      if (_paymentStatus == PaymentStatus.waitingForInput &&
          status == PaymentStatus.ready) {
        print('Payment Collection appears to be cancelled');
      }
      setState(() => _paymentStatus = status);
    });
payminty-shaun commented 11 months ago

Here is the log from cancelling the Stripe Terminal full screen prompt with debug logging on:

I/flutter (25742): Payment Status Changed from PaymentStatus.ready to waitingForInput
I/flutter (25742): Lifecycle Change: App is inactive
I/flutter (25742): Lifecycle Change: App is not visible to the user
I/flutter (25742): Lifecycle Change: App is in the background but still running
I/StripeTerminal(25742): class=TerminalStatusManager message=endPaymentFlow.
D/StripeTerminal(25742): class=ProxyTerminalListener message=onPaymentStatusChange(READY)
E/StripeTerminal(25742): class=TerminalSession
E/StripeTerminal(25742): com.stripe.stripeterminal.external.models.TerminalException: Contactless transaction was canceled
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter.collectPaymentMethodHandler(CotsAdapter.kt:172)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter.collectPaymentMethod(CotsAdapter.kt:136)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.adapter.ProxyAdapter.collectPaymentMethod(ProxyAdapter.kt:144)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$CollectPaymentMethodOperation.executeIfNotCanceled(TerminalSession.kt:1297)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$CancelableOperation.execute(TerminalSession.kt:1058)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$ExternalOperation.run$terminalsession_release(TerminalSession.kt:1016)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession.enqueueOperation$lambda$6(TerminalSession.kt:875)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession.$r8$lambda$6lM7341_XI6PEqXfOM-yc2U5tkQ(Unknown Source:0)
E/StripeTerminal(25742):    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$$ExternalSyntheticLambda0.run(Unknown Source:4)
E/StripeTerminal(25742):    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:487)
E/StripeTerminal(25742):    at java.util.concurrent.FutureTask.run(FutureTask.java:264)
E/StripeTerminal(25742):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
E/StripeTerminal(25742):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
E/StripeTerminal(25742):    at java.lang.Thread.run(Thread.java:1012)
I/flutter (25742): Payment Status Changed from PaymentStatus.waitingForInput to ready
I/flutter (25742): Payment Collection appears to be cancelled

If it's not a problem with this plugin then perhaps I need to raise an issue on the Stripe Terminal SDK. I'll see if I can test the base example app, and on another device...

payminty-shaun commented 11 months ago

Ok, it appears that this was an issue with the debug build I was running from my dev machine. When the app is built, this issue does not occur.

BreX900 commented 11 months ago

A thousand thanks. I'm closing because at most it's an SDK problem

payminty-shaun commented 11 months ago

Awesome thank you! :)