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

纯SwiftUI项目中如何正确展示PKPaymentAuthorizationViewController?现有方案遇阻

解决SwiftUI中Apple Pay展示的布局与触发问题

嘿,我太熟悉你遇到的这个问题了——用sheet展示Apple Pay原生控制器时布局拉胯,换overlay虽然样式对了但按钮点了没反应,而且旧的present方法还失效了。这其实是SwiftUI和UIKit交互时的常见适配问题,我给你两个靠谱的解决方案:

方案一:搞定Overlay的触发逻辑

Overlay本身默认是隐藏的,你需要用状态变量精准控制它的显隐,还要确保Apple Pay完成后能把状态重置回来。先修改你的ContentView:

public struct ContentView: View { 
    @ObservedObject var model: RootViewModel 
    @State private var tappedDonate = false 
    
    public var body: some View { 
        Button(action: { tappedDonate = true }, label: { 
            Text("Donate") 
                .frame(width: 300, height: 44, alignment: .center) 
        }) 
        .frame(width: 300, height: 20, alignment: .center) 
        .padding() 
        .background(Color.black) 
        .foregroundColor(.white) 
        .cornerRadius(22)
        // 用状态控制overlay的显示与隐藏
        .overlay(alignment: .center) {
            if tappedDonate {
                ApplePayWrapper(request: model.buildApplePayment(), isPresented: $tappedDonate)
                    .background(Color.clear)
            }
        }
    } 
    
    public init(model: RootViewModel) { 
        self.model = model 
    } 
}

然后给你的ApplePayWrapper加个绑定变量,用来通知父视图同步关闭状态:

struct ApplePayWrapper: UIViewControllerRepresentable {
    let request: PKPaymentRequest
    @Binding var isPresented: Bool // 新增绑定,同步显隐状态
    
    func makeUIViewController(context: Context) -> PKPaymentAuthorizationViewController {
        guard let vc = PKPaymentAuthorizationViewController(paymentRequest: request) else {
            // 处理请求无效的情况,返回空VC或做错误提示
            return UIViewController()
        }
        vc.delegate = context.coordinator
        return vc
    }
    
    func updateUIViewController(_ uiViewController: PKPaymentAuthorizationViewController, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, PKPaymentAuthorizationViewControllerDelegate {
        let parent: ApplePayWrapper
        
        init(_ parent: ApplePayWrapper) {
            self.parent = parent
        }
        
        // 支付完成/取消时,关闭VC并重置状态
        func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
            controller.dismiss(animated: true) {
                self.parent.isPresented = false
            }
        }
        
        // 实现支付授权逻辑,根据实际业务调整
        func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
            // 这里处理支付验证逻辑,比如调用后端接口
            completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
        }
    }
}

这样点击按钮后overlay会正常弹出Apple Pay,支付完成后状态自动重置,下次点击依然能正常触发。

方案二:修复Sheet的布局问题

如果你还是想用sheet,问题大概率是原生VC没有适配SwiftUI的sheet容器。试试给ApplePayWrapper加上忽略安全区域的设置:

.sheet(isPresented: $tappedDonate) {
    ApplePayWrapper(request: model.buildApplePayment())
        .background(Color.clear)
        .edgesIgnoringSafeArea(.all)
}

另外别忘了检查PKPaymentRequest的配置——比如merchantIdentifier是否和开发者后台一致,supportedNetworks有没有添加全,这些配置错误也会导致展示异常。

关键提醒

  • 不管用哪种方式,都要确保ApplePayWrapper的代理回调正确触发,不然状态变量会一直停留在true,导致后续点击按钮无反应
  • 测试时一定要用支持Apple Pay的设备或配置好的模拟器,普通模拟器可能会出现各种奇怪的问题

内容的提问来源于stack exchange,提问作者Lucas van Dongen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 10:27:51