SwiftUI接入Checkout.com Apple Pay时支付中关闭页面无法获取结果怎么办
问题根因
你当前遇到的异常是因为PKPaymentAuthorizationController的关闭回调(paymentAuthorizationControllerDidFinish)和你调用Checkout接口的异步处理逻辑是并行的:当用户在Checkout接口返回前主动关闭支付控制器,你现有的逻辑会直接在关闭时给startPayment的回调返回false,但此时Checkout的处理还在进行,后续拿到成功结果时已经没有可以触发的回调通知View层了。
解决方案
你可以通过保留待触发的回调、标记支付处理状态的方式,实现无论用户是否提前关闭支付控制器,都能返回真实的支付结果,具体修改如下:
1. 为支付处理类新增状态存储属性
首先在你的PaymentHandler类中增加属性,用来保存待触发的支付回调、标记当前是否有正在处理的支付请求:
class PaymentHandler: NSObject, PKPaymentAuthorizationControllerDelegate { // 原有属性保持不变 var checkoutFailure = false var failureMsg = "" var paymentID = "" // 新增属性:存储待触发的支付完成回调 private var pendingPaymentCompletion: ((Bool) -> Void)? // 新增属性:标记是否有正在处理的Checkout支付请求 private var isProcessingPayment = false }
2. 修改startPayment方法,持久化存储回调
原来的startPayment方法里的回调是局部变量,修改为存储到上面新增的实例属性中:
func startPayment(total: Double, custmName: String, order: Orders, completion: @escaping (Bool) -> Void) { // 原有初始化PKPaymentRequest、调起支付控制器的逻辑保持不变 // 将回调存储到实例属性,避免支付控制器关闭后被释放 self.pendingPaymentCompletion = completion self.isProcessingPayment = false }
3. 修改didAuthorizePayment逻辑,标记处理状态
在收到Apple Pay授权、开始调用Checkout接口时标记支付处理中,接口返回后再触发存储的回调:
func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) { isProcessingPayment = true // 标记开始处理支付,关闭控制器时不要立刻返回失败 checkout.processPayment(body: payment.token.paymentData) { [weak self] success, msg, id in guard let self = self else { return } DispatchQueue.main.async { self.failureMsg = msg self.paymentID = id self.checkoutFailure = !success // 触发存储的回调,返回真实支付结果 self.pendingPaymentCompletion?(success) self.pendingPaymentCompletion = nil self.isProcessingPayment = false } if success { self.orderObject.sendToDB(custmName: self.custmName, paymentID: self.paymentID) completion(PKPaymentAuthorizationResult(status: .success, errors: nil)) } else { completion(PKPaymentAuthorizationResult(status: .failure, errors: [])) } } }
4. 实现paymentAuthorizationControllerDidFinish代理方法
这个方法是支付控制器关闭时一定会触发的回调,在这里判断如果没有正在处理的支付再返回失败:
func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) { controller.dismiss(animated: true) // 只有没有正在处理的支付时,才判定为用户主动取消,返回失败 if !isProcessingPayment { pendingPaymentCompletion?(false) pendingPaymentCompletion = nil checkoutFailure = true } }
额外优化建议
- 给Checkout的支付请求增加超时逻辑(比如15秒超时),超时后主动触发回调返回失败,避免回调长期挂起占用内存
- 后端增加订单状态查询接口,用户进入订单列表页时主动拉取对应订单的支付状态,避免极端场景下回调丢失导致的状态不一致
内容的提问来源于stack exchange,提问作者malik
相关产品推荐
相关产品推荐

