You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:54:56