React Native iOS集成Apple Pay时模态框立即消失问题排查
Apple Pay模态框在UI Kitten环境下立即消失:原因与修复方案
问题原因
- 启用UI Kitten时,
RCTPresentedViewController()返回的是RCTModalHostViewController——这是React Native用于封装模态视图的容器控制器。 - 系统级的
PKPaymentAuthorizationViewController(Apple Pay模态框)需要挂载在原生UIKit顶层视图控制器上才能正常展示,RCTModalHostViewController的内部生命周期和层级管理逻辑会干扰Apple Pay模态框的存在,导致其弹出后立即被自动dismiss。 - 移除UI Kitten后,
RCTPresentedViewController()返回标准UIViewController,符合Apple Pay模态框的展示要求,因此功能正常。
修复方案
方案1:实现顶层视图控制器递归获取逻辑
替换依赖RCTPresentedViewController()的方式,自行实现工具方法获取真正的顶层原生视图控制器:
internal class OppwaHandler: NSObject, UINavigationControllerDelegate, OPPThreeDSEventListener, PKPaymentAuthorizationViewControllerDelegate { // 替换原有的let viewController = RCTPresentedViewController() private func getTopMostViewController() -> UIViewController? { // 获取当前活跃窗口的根控制器 guard let windowScene = UIApplication.shared.connectedScenes .filter({ $0.activationState == .foregroundActive }) .first as? UIWindowScene, let keyWindow = windowScene.windows.filter({ $0.isKeyWindow }).first else { return nil } var topVC = keyWindow.rootViewController // 递归找到最顶层的已present控制器 while let presentedVC = topVC?.presentedViewController { topVC = presentedVC // 如果遇到RCTModalHostViewController,直接取它内部的presented控制器(如果存在) if let rctModalVC = topVC as? RCTModalHostViewController { topVC = rctModalVC.presentedViewController ?? rctModalVC } } return topVC } public func onApplePay(params: ApplePayParams) -> String { // ... 原有无关代码 guard let rootViewController = getTopMostViewController(), let vc = PKPaymentAuthorizationViewController(paymentRequest: request) else { return rootViewController == nil ? "Not showing view controller" : "Apple Pay not supported." } vc.delegate = self DispatchQueue.main.async { rootViewController.present(vc, animated: true, completion: nil) } return "Ok. reached end of ok logic" } // ... 其他原有代码 }
方案2:直接获取React Native根控制器
如果你的App架构中React Native根控制器是RCTRootViewController,可以直接定位到它,再获取其顶层present控制器:
private func getRCTRootViewController() -> UIViewController? { guard let windowScene = UIApplication.shared.connectedScenes .filter({ $0.activationState == .foregroundActive }) .first as? UIWindowScene, let keyWindow = windowScene.windows.filter({ $0.isKeyWindow }).first else { return nil } var rootVC = keyWindow.rootViewController // 找到RCTRootViewController while let parentVC = rootVC?.parent { rootVC = parentVC if rootVC is RCTRootViewController { break } } // 再找它的顶层present控制器 while let presentedVC = rootVC?.presentedViewController { rootVC = presentedVC } return rootVC }
注意事项
- 必须保留
DispatchQueue.main.async,确保模态框present操作在主线程执行(UI操作必须在主线程)。 - 确认
PKPaymentAuthorizationViewControllerDelegate的所有必要方法已正确实现,例如paymentAuthorizationViewControllerDidFinish(_:),避免因代理未处理导致的异常dismiss。
内容的提问来源于stack exchange,提问作者Obay Abd-Algader
相关产品推荐
相关产品推荐

