Home
avatar

SNOUX·雪飞

ApplePayKit:一个简单易用的 Apple Pay Swift Package

ApplePayKit

是一个面向 iOS 16+ 的轻量 Apple Pay Swift Package。它负责构建支付请求、检查设备能力、展示系统支付面板,并把支付令牌交给你的服务端授权逻辑。

核心业务与视图组件分为三个独立模块:

  • ApplePayKit:配置、请求构建、能力检查和授权流程。
  • ApplePayKitSwiftUI:基于官方 PayWithApplePayButton 的可选 SwiftUI 按钮。
  • ApplePayKitUIKit:基于官方 PKPaymentButton 的可选 UIKit 按钮。

只想使用自己的支付按钮时,仅引入 ApplePayKit 即可。

接入前准备

  1. 在 Apple Developer 后台创建 Merchant ID 和支付处理证书。
  2. 在 App Target 的 Signing & Capabilities 中添加 Apple Pay,勾选同一个 Merchant ID。
  3. 在支付服务商或自有服务端完成 Apple Pay 证书与令牌处理配置。
  4. 将本仓库作为 Swift Package 添加到项目,并按界面技术选择核心及视图产品。

Apple Pay 返回的支付令牌必须发送到可信服务端或支付服务商处理。不要仅凭客户端回调发货,也不要把证书私钥放进 App。

最简用法

建议把 ApplePayClient 保存为页面或支付服务的强引用属性,直到支付流程结束。

import Foundation
import ApplePayKit
import PassKit

@MainActor
final class CheckoutService {
    private let applePay = ApplePayClient(
        configuration: ApplePayConfiguration(
            merchantIdentifier: "merchant.com.yourcompany.app",
            countryCode: "CN",
            currencyCode: "CNY",
            supportedNetworks: [.chinaUnionPay, .visa, .masterCard],
            merchantCapabilities: [.threeDSecure, .emv]
        )
    )

    func pay() {
        applePay.present(
            items: [
                ApplePayItem(label: "高级会员", amount: 98),
                ApplePayItem(label: "优惠", amount: -10)
            ],
            total: ApplePayItem(label: "示例", amount: 88),
            applicationData: Data("order-1001".utf8),
            authorizationHandler: { payment in
                // 把 payment.token.paymentData 上传到你的服务端。
                try await PaymentAPI.confirmApplePay(
                    tokenData: payment.token.paymentData
                )
                return PKPaymentAuthorizationResult(status: .success, errors: [])
            },
            onSuccess: { payment in
                print("支付完成:\(payment.token.transactionIdentifier)")
            },
            onFailure: { error in
                // 取消、配置错误、设备不可用和授权失败都会进入这里。
                print(error.localizedDescription)
            }
        )
    }
}

原有 completion: (Result<PKPayment, ApplePayError>) -> Void 接口仍然保留,方便需要统一结果流的项目继续使用。

支付按钮

ApplePayKit 不限制支付入口。无论使用哪种按钮,都只需在点击事件中调用上面的 CheckoutService.pay()

SwiftUI

SwiftUI 项目添加 ApplePayKitSwiftUI 产品,然后使用封装后的官方按钮:

import ApplePayKitSwiftUI
import PassKit
import SwiftUI

ApplePayButton(.buy, style: .black) {
    checkoutService.pay()
}
.frame(height: 48)

UIKit

UIKit 项目添加 ApplePayKitUIKit 产品,然后使用封装后的官方按钮:

import ApplePayKitUIKit
import UIKit

final class CheckoutViewController: UIViewController {
    private let checkoutService = CheckoutService()

    private lazy var applePayButton = ApplePayButtonView(
        type: .buy,
        style: .black,
        cornerRadius: 8
    ) { [weak self] in
        self?.checkoutService.pay()
    }
}

自定义支付入口

已有按钮、订单列表或统一收银台也可以直接触发业务层:

import ApplePayKit

Button("确认支付") {
    checkoutService.pay()
}

如果按钮明确用于 Apple Pay,应遵循 Apple Pay 按钮的品牌与界面规范;自定义入口不会改变 ApplePayKit 的支付处理方式。

可用性检查

switch applePay.availability() {
case .available:
    // 展示 Apple Pay 按钮
case .supportedCardUnavailable:
    // 可提示用户先在 Wallet 中添加受支持的银行卡
case .applePayUnavailable:
    // 隐藏 Apple Pay 入口或提供其他支付方式
}

高级请求

周期付款、延迟付款或需要进一步修改 PKPaymentRequest 时,可先调用 makeRequest,设置 PassKit 的高级字段后,再通过 present(request:authorizationHandler:completion:) 展示。

测试说明

支付面板与真实扣款必须在支持 Apple Pay 的设备、正确签名的 App、沙盒测试卡及可用的支付服务端环境中验证。单元测试和模拟器构建只能验证请求构建及编译正确性,不能证明真实支付链路成功。

Apple 官方资料

::[设置 Apple Pay]{link=“https://developer.apple.com/documentation/passkit/setting-up-apple-pay” type=“info”} ::[在 App 中提供 Apple Pay]{link=“https://developer.apple.com/documentation/passkit/offering-apple-pay-in-your-app” type=“info”} ::[支付令牌格式]{link=“https://developer.apple.com/documentation/passkit/payment-token-format-reference” type=“info”}

SwiftUI iOS 技术