Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The app freezes when a modal is shown after completing an Apple Pay payment #445

Closed
ChielBruin opened this issue May 21, 2024 · 13 comments
Closed
Labels
bug report when a bug report is created

Comments

@ChielBruin
Copy link

ChielBruin commented May 21, 2024

Describe the bug
When I complete an Apple Pay payment, the drop-in closes but the app is completely unresponsive.
The payment itself did succeed.

To Reproduce
Steps to reproduce the behavior:

  1. Start a payment
  2. Complete the payment using Apple Pay, the drop-in closes
  3. The app is now unresponsive (also the on-success callbacks are never called)

Expected behavior
The app should function normally after completing a payment (which in our case would show a pop-up telling the user that the payment succeeded)

Logs
I get the following error messages in my logs:

2024-05-21 13:46:49.105899+0200 X[446:34715] [ProcessSuspension] 0x1149b8b40 - ProcessAssertion: Failed to acquire RBS Background assertion 'WebProcess Background Assertion' for process with PID 448, error: Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}
2024-05-21 13:46:51.077988+0200 X[446:34715] [Presentation] Attempt to present <RCTModalHostViewController: 0x108aa4b30> on <UIViewController: 0x108b17d40> (from <UIViewController: 0x108b17d40>) which is already presenting <Adyen.DropInNavigationController: 0x109957400>.
2024-05-21 13:46:52.215488+0200 X[446:35296] [tcp] tcp_input [C17.1:3] flags=[R] seq=3993052042, ack=0, win=0 state=CLOSED rcv_nxt=3993052042, snd_una=3676108723
2024-05-21 13:46:52.216416+0200 X[446:35296] [tcp] tcp_input [C12.1:3] flags=[R] seq=1152004211, ack=0, win=0 state=CLOSED rcv_nxt=1152004211, snd_una=408956273
2024-05-21 13:47:19.104813+0200 X[446:34715] Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
2024-05-21 13:47:19.112128+0200 X[446:34715] Could not signal service com.apple.WebKit.Networking: 113: Could not find specified service

It seems to fail to overwrite the drop-in in the view stack

Devices:

  • Version 2.0.0-rc1
  • Device: iPhoneX using an Apple Sandbox account
  • OS: iOS 16.7.8

Additional context
The shown behaviour is similar to an issue with integrating Apple Pay that I had in a different library, but they are probably unrelated: mkharibalaji/react-native-adyen-payment#54

@ChielBruin ChielBruin added the bug report when a bug report is created label May 21, 2024
@descorp
Copy link
Contributor

descorp commented May 27, 2024

Hey @ChielBruin

Complete the payment using Apple Pay, the drop-in closes

The app is now unresponsive (also the on-success callbacks are never called)

The expected way to dismiss DropIn/Component UI is to call nativeComponent.hide(success) in successs/failer callback.

Are you using /sessions or /payments flow?
Do you receive any callback after click "Pay" in the ApplePay Sheet ?

@ChielBruin
Copy link
Author

ChielBruin commented May 27, 2024

We use the advanced flow like shown in the README and example app:

class Client {
  
  public async payments(
    data: PaymentMethodData,
    component: AdyenActionComponent,
    _extra: unknown,
  ): Promise<undefined | PaymentResponse> {
    const body = {
      ...data,
      ...this.config,
      recurringProcessingModel: 'CardOnFile',
      channel: Platform.OS === 'ios' ? 'iOS' : 'Android',
    };

    const response = await this.request(body, '/payments');

    if (response.action) {
      component.handle(response.action);
      return undefined;
    } else {
      this.handleResponse(response, component);
      return response;
    }
  }

  public async paymentsDetails(
    data: PaymentDetailsData,
    component: AdyenActionComponent,
  ): Promise<undefined | PaymentResponse> {
    const response = await this.request(data, '/payments/details');
    this.handleResponse(response, component);

    return response;
  }

  private async request(data: object, path: string): Promise<any> {
    const response = await request
      .agent()
      .post(this.baseUrl + path)
      .set('Content-Type', 'application/json')
      .send(data)
      .ok(() => true);

    if (response.status !== Http.OK) {
      console.error(response.body);
      throw new Error(response.body);
    }

    return response.body;
  }

  private handleResponse(
    response: PaymentResponse,
    component: AdyenActionComponent,
  ): void {
    const success = [
      ResultCode.authorised,
      ResultCode.received,
      ResultCode.pending,
      ResultCode.presentToShopper,
    ].includes(response.resultCode as ResultCode);

    component.hide(success);
    if (!success) {
      throw response;
    }
  }
}
  <AdyenCheckout
        config={client.config}
        paymentMethods={paymentMethods}
        onSubmit={(...args) =>
          client
            .payments(...args)
            .then((response) => {
                // Show success/error message
            }).catch((ex) => {
                // Show error message
            })
        }
        onAdditionalDetails={(...args) =>
          client
            .paymentsDetails(...args)
            .then((response) => {
                // Show success/error message
            }).catch((ex) => {
                // Show error message
            })
        }
        onError={(error, component) => {
          component.hide(false);
          // Show error message
        }}
      >

This works perfectly for iDEAL and creditcard payments, but not for Apple Pay.
We do not get any of the callbacks called that I would expect to be called (I even tried the onComplete that is voucher-only according to the docs). It just logs the error I posted at the top about not being able to replace the drop-in with a different screen.

@descorp
Copy link
Contributor

descorp commented May 28, 2024

In your code you are missing component.hide(false); in case the request have failed. But overall looks good.

One suggestion - use useCallback. This will make sure only one instance of a function exist.

2024-05-21 13:46:51.077988+0200 X[446:34715] [Presentation] Attempt to present <RCTModalHostViewController: 0x108aa4b30> on <UIViewController: 0x108b17d40> (from <UIViewController: 0x108b17d40>) which is already presenting <Adyen.DropInNavigationController: 0x109957400>.

Seems like something is trying to present RCTModalHostViewController but do not expect to see our DropInNavigationController there 🤔

Are you using any 3rd-party libraries for spinner or loading bar during network call, maybe?
I wonder if there is something causing re-rendering "behind the scene" 🤔

Could you make a console.log in here and check if your AdyenCheckout got re-rendered ?

@ChielBruin
Copy link
Author

Thanks for spotting the missing call to hide()! But sadly that wasn't the issue and converting to using useCallback didn't solve it either.

I added some logs to see what re-renders are triggered:

  • Our payment screen (both initial mount [1] and each re-render [2])
  • AdyenCheckout both in the cleanup function you linked [3] to and outside of that useEffect[4] to see if re-renders at all

I found that I got message 2 and 4 a couple ms before the "Attempt to present"-error

Regarding other libraries:

  • We show a simple loading animation on the payment button using React Native Reanimated
  • Right after payment completion we show a Modal with a success/error message, but in this case we do not get to this point as we receive no callback that triggers this one

@descorp
Copy link
Contributor

descorp commented May 28, 2024

Is it possible for you to create a blank app and reproduce this behaviour there?

@camil-adyen
Copy link

Hey @ChielBruin, do you still face this issue with the latest releases?

@ChielBruin
Copy link
Author

I just tried with version 2.2.0 and still see the same issue

Do you know if other user have gotten ApplePay to work (meaning I probably missed some configuration step somewhere)?

@descorp
Copy link
Contributor

descorp commented Aug 14, 2024

Hey @ChielBruin

It is confirmed to work.
At least problem described in this ticket seems unique.
Mostly, people struggling with setting up Apple Pay.


I just tried with version 2.2.0 and still see the same issue

I believe this could be a "re-render" issue. Something is mutating state of your "parent" view and it causes recreation of AdyenCheckout.

Is it possible for you to create a blank app and reproduce this behaviour there?
This would allow us to debug and hopfully find a solution.

@ChielBruin
Copy link
Author

I've narrowed down the issue to the popups we show upon payment completion using the react-native-modal library. As soon as I comment out usage of the modal Apple pay works normally, so the issue might be related to this issue with multiple modals.
The weird thing however is that displaying this modal for any other payment method does not result in the app freezing.

@descorp
Copy link
Contributor

descorp commented Aug 15, 2024

ApplePay is a bit unique - it is not a standard UIViewController: it is another window, running in a separate thread, appearing above your screen. With other VC, 3rd party library (we do that, for example) can traverse view hierarchy and present itself on top, but it is not possible with Apple Pay.

Maybe this is what causing this collision on iOS level

@ChielBruin ChielBruin changed the title [2.0.0-rc1] The app is frozen after the drop-in closes when completing an Apple Pay payment The app freezes when a modal is shown after completing an Apple Pay payment Aug 16, 2024
@descorp
Copy link
Contributor

descorp commented Aug 29, 2024

Hey @ChielBruin

Any luck?

@ChielBruin
Copy link
Author

I have not been able to spend more time on it after I figured out what was causing the issue. It might be worth checking what https://github.com/mkharibalaji/react-native-adyen-payment does differently in their Apple Pay implementation, as we did not see the same issue with multiple modals when using that library. But I am not sure when I can spend time on that due to other priorities

@camil-adyen
Copy link

Closing this issue for now. Feel free to reopen when it becomes relevant again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug report when a bug report is created
Projects
None yet
Development

No branches or pull requests

3 participants