Make `hide(true|false)` async to resolve Apple Pay dismiss
Describe the bug I have done a transaction via Apple Pay on a real device. After a successful transaction, when I go for the next transaction again and try to open Apple Pay again, it does not open. start('applepay')
To Reproduce Steps to reproduce the behavior:
- Go for transaction via apple pay
- even it's fail or successful. then again for for another transaction
- apple pay is not opening
Expected behavior it should open the apple pay even for second payment
Screenshots
Smartphone (please complete the following information):
- Device: iphone
- Adyen sdk version: 2.4.0
Additional context Error on xcode: [Presentation] Attempt to present <PKPaymentAuthorizationViewController: 0x107d23f00> on <RNSScreen: 0x106e9edf0> (from <RNSScreen: 0x106e9edf0>) whose view is not in the window hierarchy.
i'm suspecting an issue on this block.
internal func present(_ component: PresentableComponent) {
guard let presenter = BaseModule.currentPresenter ?? UIViewController.topPresenter else { return sendEvent(error: NativeModuleError.notKeyWindow) }
defer {
BaseModule.currentPresenter = presenter
}
guard component.requiresModalPresentation else {
presenter.present(component.viewController, animated: true)
return
}
let navigation = UINavigationController(rootViewController: component.viewController)
component.viewController.navigationItem.rightBarButtonItem = .init(barButtonSystemItem: .cancel,
target: self,
action: #selector(cancelDidPress))
presenter.present(navigation, animated: true)
}
it's going to else condition in guard component.requiresModalPresentation else { presenter.present(component.viewController, animated: true) return }
Hey @faizantariq2
it's going to else condition in
guard component.requiresModalPresentation else { ... }
That is expected behaviour. ApplePay Sheet do not require UINavigationController
[Presentation] Attempt to present <PKPaymentAuthorizationViewController: 0x107d23f00> on <RNSScreen: 0x106e9edf0> (from <RNSScreen: 0x106e9edf0>) whose view is not in the window hierarchy.
This means presenter is not in the window hierarchy. I only see two explanations
- previous
BaseModule.currentPresenterwas not cleaned (do you callnativeComponent.hide(success)?) - window hierarchy is somehow messed up (make a breakpoint and check "Debug View Hierarchy" in both cases).
- yes, we call nativeComponent.hide(success) this.
This problem only occurs when we use Apple Pay. Everything works fine with other payment methods like card , Blik etc. Regardless of what I do, other payment methods function correctly.
The issue arises when I use Apple Pay to complete a transaction. Upon returning for a second attempt to use Apple Pay or even the drop-in feature, it fails to open
Could you compare the view hierarchy of the first and second Apple Pay attempts?
In a video I received from the Support team, I noticed that the Apple Pay sheet was dismissed very quickly. My theory is that there may not be enough time to call BaseModule.currentPresenter = nil (see https://github.com/Adyen/adyen-react-native/blob/develop/ios/Components/BaseModule.swift#L149-L151) upon dismissal. If this is the case, it could lead to unexpected results on Apple's side.
Could you try adding a half-second delay before calling nativeComponent.hide(success)?
Hi @descorp
We tried adding delay as suggested, but still same scenario, Apple pay is not opening second time.
Here I am attaching Xcode logs, might be these logs can help you to reach the root cause.
2025-03-19 12:01:07.392214+0000 storybookMobileSIT[534:28008] Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
2025-03-19 12:01:09.358691+0000 storybookMobileSIT[534:28226] [javascript] EventEmitter.removeListener('didUpdateDimensions', ...): Method has been deprecated. Please instead use `remove()` on the subscription returned by `EventEmitter.addListener`.
2025-03-19 12:01:10.876976+0000 storybookMobileSIT[534:28008] [Presentation] Attempt to present <PKPaymentAuthorizationViewController: 0x109057a60> on <RNSScreen: 0x1090565a0> (from <RNSScreen: 0x1090565a0>) whose view is not in the window hierarchy.
2025-03-19 12:01:30.581251+0000 storybookMobileSIT[534:28008] Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service`
EventEmitter.removeListener('didUpdateDimensions', ...): Method has been deprecated. Please instead use
remove()on the subscription returned byEventEmitter.addListener.
Thanks for reporting, I wasn't aware this one is deprecated. However it is not part of the problem.
[Presentation] Attempt to present <PKPaymentAuthorizationViewController: 0x109057a60> on <RNSScreen: 0x1090565a0> (from <RNSScreen: 0x1090565a0>) whose view is not in the window hierarchy.
This is the problem. Could you make a breakpoint in this line and see if it is called?
Hi @descorp
I tried putting breakpoint, but this line is not being called anytime.
And on a like 141 ?
This problem happens because dismiss is async and there is no way to tell when it is finished.
We tried adding delay as suggested, but still same scenario, Apple pay is not opening second time.
Probably my first instruction was incorrect. Could you try adding a half-second delay after calling nativeComponent.hide(success), but before any navigation logic?
Hi @descorp
After adding delay of 1 second, this line is being executed every-time and Apple pay is opening all the time as expected.: BaseModule.currentPresenter = nil
Can we avoid adding delay? Can you push this fix in newer version, so we don't have to use delays.
Hey @ahsan-lebara
Thanks for confirming! We were aware of this problem, but holistic fix would require a breaking change that we can only address in a major version.
Because this is asynchronous call, there is nothing we currently do from SDK side, the fix can only be applied on app level.
I'll keep you posted on any future developments.
Could this also be causing the app-freezes I see in #445, since both are caused by timing issues in the closing of the ApplePay sheet?
Hey @ChielBruin
This could be, actually - a race condition prevents Apple Pay VC to be dismissed and messing with VC stack and further navigation. Could you check if this is the case?
Something simple like:
const onSubmit = useCallback( (data, nativeComponent ) => {
// Make /paymens call
nativeComponent.hide(isSuccess);
if (data.paymentMethod.type === 'applepay') {
await sleep(1000);
}
// navigate further
}, [some, dependency]);