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

Swift集成Apple Pay:didAuthorizePayment代理支付服务端验证疑问

Apple Pay Swift集成:支付验证与服务器交互实现

在Apple Pay的集成流程中,客户端并不直接与Apple支付服务器交互验证,而是需要将Apple生成的支付令牌提交给你的后端服务,由后端完成与Apple支付系统的验证和后续扣款逻辑。以下是具体实现方案:

一、客户端提取支付令牌并提交到服务器

在didAuthorizePayment代理方法中,核心是获取PKPayment对象里的支付令牌,再通过HTTP请求发送到你的后端接口。更新后的代码示例:

func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
    // 显示加载状态
    loader.startAnimating()
    lblLoading.isHidden = false
    
    // 提取支付令牌并转为可传输格式
    guard let paymentData = payment.token.paymentData as? [String: Any],
          let tokenData = try? JSONSerialization.data(withJSONObject: paymentData, options: []),
          let tokenBase64 = tokenData.base64EncodedString(options: .endLineWithLineFeed) else {
        let error = NSError(domain: "PaymentError", code: 1001, userInfo: [NSLocalizedDescriptionKey: "支付令牌解析失败"])
        completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
        loader.stopAnimating()
        lblLoading.isHidden = true
        return
    }
    
    // 组装请求参数(根据业务需求添加订单ID、用户信息等)
    let requestParams: [String: Any] = [
        "paymentToken": tokenBase64,
        "totalAmount": totalAmount,
        "currencyCode": paymentRequest.currencyCode,
        "orderId": "ORDER_20240520_001" // 替换为你的唯一订单ID
    ]
    
    // 构造服务器请求
    guard let url = URL(string: "https://你的后端域名/api/apple-pay/verify") else {
        let error = NSError(domain: "NetworkError", code: 1002, userInfo: [NSLocalizedDescriptionKey: "无效的服务器地址"])
        completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
        loader.stopAnimating()
        lblLoading.isHidden = true
        return
    }
    
    var urlRequest = URLRequest(url: url)
    urlRequest.httpMethod = "POST"
    urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: requestParams, options: [])
    
    // 发起网络请求
    let task = URLSession.shared.dataTask(with: urlRequest) { [weak self] data, response, error in
        DispatchQueue.main.async {
            self?.loader.stopAnimating()
            self?.lblLoading.isHidden = true
            
            guard let self = self else { return }
            
            // 处理网络错误
            if let error = error {
                completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
                return
            }
            
            // 处理服务器响应状态码
            guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
                let error = NSError(domain: "ServerError", code: 1003, userInfo: [NSLocalizedDescriptionKey: "服务器验证失败"])
                completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
                return
            }
            
            // 解析服务器返回的验证结果
            if let data = data {
                do {
                    if let result = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
                       let isSuccess = result["success"] as? Bool, isSuccess {
                        // 验证成功,通知Apple Pay完成授权
                        completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
                        // 这里可添加订单成功后的页面跳转逻辑
                    } else {
                        let error = NSError(domain: "PaymentError", code: 1004, userInfo: [NSLocalizedDescriptionKey: "支付验证未通过"])
                        completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
                    }
                } catch {
                    let error = NSError(domain: "ParseError", code: 1005, userInfo: [NSLocalizedDescriptionKey: "结果解析失败"])
                    completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
                }
            } else {
                let error = NSError(domain: "ServerError", code: 1006, userInfo: [NSLocalizedDescriptionKey: "服务器未返回有效数据"])
                completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
            }
        }
    }
    task.resume()
}

二、后端验证流程说明

你的后端服务需要完成以下步骤:

  • 接收客户端发送的支付令牌和业务参数
  • 向Apple的支付验证端点发起请求:测试阶段使用沙箱环境端点,正式上线切换为生产环境端点
  • 提交格式为{"payment-token": "客户端传来的base64令牌"}的JSON参数
  • 解析Apple返回的响应:若status字段为0,则表示令牌有效,此时可执行扣款、更新订单状态等操作;非0值则表示验证失败
  • 将验证结果(成功/失败)返回给客户端

三、关键注意事项

  • HTTPS强制要求:所有支付相关网络请求必须使用HTTPS协议,防止敏感数据泄露
  • 环境区分:测试时使用Apple沙箱账号,上线前务必切换到生产环境的验证端点
  • 错误覆盖:要处理令牌解析失败、网络异常、服务器错误、Apple验证失败等所有可能的异常场景,给用户明确提示
  • 订单幂等性:确保订单ID唯一,避免重复提交导致的重复扣款问题

内容的提问来源于stack exchange,提问作者Saravanan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:31:19