
passkit
热门使用 PassKit 集成 Apple Pay 支付和 Wallet 凭证(Passes)。适用于添加 Apple Pay 按钮、创建支付请求、处理支付授权、将凭证添加到 Wallet、配置商户能力、管理收货/联系人字段,或者处理 PKPaymentRequest、PKPaymentAuthorizationController、PKPaymentButton、AddPassToWalletButton、PKPass、PKAddPassesViewController、PKPassLibrary、Wallet 凭证分发,以及实体商品、线下服务、捐赠和符合条件的订阅/定期支付等 Apple Pay 结账流程。
使用 PassKit 集成 Apple Pay 支付和 Wallet 凭证(Passes)。适用于添加 Apple Pay 按钮、创建支付请求、处理支付授权、将凭证添加到 Wallet、配置商户能力、管理收货/联系人字段,或者处理 PKPaymentRequest、PKPaymentAuthorizationController、PKPaymentButton、AddPassToWalletButton、PKPass、PKAddPassesViewController、PKPassLibrary、Wallet 凭证分发,以及实体商品、线下服务、捐赠和符合条件的订阅/定期支付等 Apple Pay 结账流程。
PassKit
使用 PassKit 接入 Apple Pay 支付(适用于实体商品、线下服务、捐赠以及符合条件的定期/自动续订支付),并将凭证添加到用户的 Wallet(钱包)中。覆盖支付按钮、支付请求、授权、Wallet 凭证及商户配置。支持 Swift 6.3 / iOS 26+。
对于高级 Apple Pay 流程,单个 PKPaymentRequest 只能设置一种可选的高级请求类型:自动续订/定期(recurring)、自动充值(automatic reload)、延迟支付(deferred)、Apple Pay Later 可用性或多令牌上下文(multi-token contexts)。如果结账时需要多种模式,请使用独立的支付请求。
目录
配置与准备
项目配置
- 在 Xcode 中开启 Apple Pay capability(能力)
- 在 Apple Developer 后台创建 Merchant ID(商户标识,格式为:
merchant.com.example.app) - 为你的 Merchant ID 生成并安装 Payment Processing Certificate(支付处理证书)
- 将 Merchant ID 添加到项目的 entitlements 中
可用性检查
在展示 Apple Pay UI 之前,务必先验证当前设备是否支持支付。如果你使用 canMakePayments(usingNetworks:capabilities:) 检查是否有可用绑卡,根据 Apple HIG(人机界面指南)规范,只要进行了这项检查,你就必须将 Apple Pay 作为主要且显眼的支付选项进行展示。
import PassKit
func canMakePayments() -> Bool {
// 检查设备本身是否支持 Apple Pay
guard PKPaymentAuthorizationController.canMakePayments() else {
return false
}
// 检查用户是否绑定了你所支持卡组织的银行卡
return PKPaymentAuthorizationController.canMakePayments(
usingNetworks: [.visa, .masterCard, .amex, .discover],
capabilities: .threeDSecure
)
}
展示 Apple Pay 按钮
SwiftUI
在 SwiftUI 中直接使用内置的 PayWithApplePayButton 视图。只要控件带有 Apple Pay 标识,就必须使用 Apple 官方提供的按钮 API;自定义按钮绝不能包含 Apple Pay Logo 或 "Apple Pay" 字样。
import SwiftUI
import PassKit
struct CheckoutView: View {
var body: some View {
PayWithApplePayButton(.buy) {
startPayment()
}
.payWithApplePayButtonStyle(.black)
.frame(height: 48)
.padding()
}
}
UIKit
在基于 UIKit 的界面中使用 PKPaymentButton。
let button = PKPaymentButton(
paymentButtonType: .buy,
paymentButtonStyle: .black
)
button.cornerRadius = 12
button.addTarget(self, action: #selector(startPayment), for: .touchUpInside)
按钮类型(Button types): .plain、.buy、.setUp、.inStore、.donate、.checkout、.continue、.book、.subscribe、.reload、.addMoney、.topUp、.order、.rent、.support、.contribute、.tip
创建支付请求
构建一个包含你的商户信息和商品明细的 PKPaymentRequest。
注意:PassKit 的金额 API 使用 NSDecimalNumber,而非 Double。
func createPaymentRequest() -> PKPaymentRequest {
let request = PKPaymentRequest()
request.merchantIdentifier = "merchant.com.example.app"
request.countryCode = "US"
request.currencyCode = "USD"
request.supportedNetworks = [.visa, .masterCard, .amex, .discover]
request.merchantCapabilities = .threeDSecure
request.paymentSummaryItems = [
PKPaymentSummaryItem(
label: "Widget",
amount: NSDecimalNumber(string: "9.99")
),
PKPaymentSummaryItem(
label: "Shipping",
amount: NSDecimalNumber(string: "4.99")
),
PKPaymentSummaryItem(
label: "My Store",
amount: NSDecimalNumber(string: "14.98")
) // 总计(Total)
]
return request
}
paymentSummaryItems 中的最后一项会被视作最终结算总价(Total),它的 label 会显示在支付弹窗的支付确认行中。
请求收货和联系人信息
只请求计价、履约或法律合规所必需的联系人字段。
如果支付弹窗(payment sheet)无法准确收集所选商品规格、可选备注、单件商品的配送目的地或自提点等信息,请在用户点击 Apple Pay 按钮之前先收集完毕。
request.requiredShippingContactFields = [.postalAddress, .emailAddress, .name]
request.requiredBillingContactFields = [.postalAddress]
let standard = PKShippingMethod(
label: "Standard",
amount: NSDecimalNumber(string: "4.99")
)
standard.identifier = "standard"
standard.detail = "5-7 business days"
let express = PKShippingMethod(
label: "Express",
amount: NSDecimalNumber(string: "9.99")
)
express.identifier = "express"
express.detail = "1-2 business days"
request.shippingMethods = [standard, express]
request.shippingType = .shipping // .delivery, .storePickup, .servicePickup
支持的卡组织/网络(Supported Networks)
| 卡组织 | 常量 |
|---|---|
| Visa | .visa |
| Mastercard | .masterCard |
| American Express | .amex |
| Discover | .discover |
| China UnionPay (中国银联) | .chinaUnionPay |
| JCB | .JCB |
| Maestro | .maestro |
| Electron | .electron |
| Interac | .interac |
可以使用 PKPaymentRequest.availableNetworks() 在运行时查询当前可用的卡组织。
弹出支付页面
使用 PKPaymentAuthorizationController(同时支持 SwiftUI 和 UIKit,无需依赖 View Controller)。控制器(controller)的 delegate 属性是 weak 弱引用,因此在支付页面展示期间请务必强持有该 controller。
final class CheckoutCoordinator: NSObject {
private var paymentController: PKPaymentAuthorizationController?
@MainActor
func startPayment() {
let controller = PKPaymentAuthorizationController(
paymentRequest: createPaymentRequest()
)
paymentController = controller
controller.delegate = self
controller.present { [weak self] presented in
if !presented {
self?.paymentController = nil
}
}
}
}
处理支付授权
实现 PKPaymentAuthorizationControllerDelegate 协议来处理支付 Token。
extension CheckoutCoordinator: PKPaymentAuthorizationControllerDelegate {
func paymentAuthorizationController(
_ controller: PKPaymentAuthorizationController,
didAuthorizePayment payment: PKPayment,
handler completion: @escaping (PKPaymentAuthorizationResult) -> Void
) {
// 将 payment.token.paymentData 发送到你的支付服务网关
Task {
do {
try await paymentService.process(payment.token)
completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
} catch {
completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
}
}
}
func paymentAuthorizationControllerDidFinish(
_ controller: PKPaymentAuthorizationController
) {
controller.dismiss { [weak self] in
self?.paymentController = nil
}
}
}
处理配送方式变更
func paymentAuthorizationController(
_ controller: PKPaymentAuthorizationController,
didSelectShippingMethod shippingMethod: PKShippingMethod,
handler completion: @escaping (PKPaymentRequestShippingMethodUpdate) -> Void
) {
let updatedItems = recalculateItems(with: shippingMethod)
let update = PKPaymentRequestShippingMethodUpdate(paymentSummaryItems: updatedItems)
completion(update)
}
Wallet 凭证
添加凭证到 Wallet
加载签名后的 .pkpass 数据,检查设备是否支持添加凭证。如果希望用户在添加前预览凭证,可以弹出 PKAddPassesViewController。PKPass(data:) 接收已签名的凭证数据,可能抛出数据无效或签名无效等错误。在审核指导文档或错误处理逻辑中,应当明确指出 invalid-data 和 invalid-signature 错误,而不是简单用一个裸 try? 默默吃掉错误。
func addPassToWallet(data: Data) {
guard PKAddPassesViewController.canAddPasses() else {
return
}
do {
let pass = try PKPass(data: data)
guard let addController = PKAddPassesViewController(pass: pass) else {
return
}
addController.delegate = self
present(addController, animated: true)
} catch {
// 签名凭证数据无效或签名无法通过验证
showRecoverablePassError(error)
}
}
SwiftUI Wallet 按钮
使用 AddPassToWalletButton 作为 UIKit 中 PKAddPassButton 的 SwiftUI 等价实现。
import PassKit
import SwiftUI
struct AddPassButton: View {
let passData: Data
@State private var addedToWallet = false
var body: some View {
if PKAddPassesViewController.canAddPasses(),
let pass = try? PKPass(data: passData) {
AddPassToWalletButton([pass]) { added in
addedToWallet = added
}
.addPassToWalletButtonStyle(.blackOutline)
.frame(width: 250, height: 50)
}
}
}
检查凭证库
使用 PKPassLibrary 检查并管理用户 Wallet 中现有的凭证。在对凭证库进行操作前先检查 PKPassLibrary.isPassLibraryAvailable(),但要判断设备是否能添加新凭证,请使用 PKAddPassesViewController.canAddPasses()。passes() 只会返回你的 App 通过 entitlements 权限有权访问的凭证。替换已有凭证时,请检查 replacePass(with:) 返回的布尔值并做好失败处理。关于签名凭证包构建、更新 Web 服务以及 replacePass(with:) 的详细说明,请参考 references/wallet-passes.md。
let library = PKPassLibrary()
// 检查特定凭证是否已在 Wallet 中
let hasPass = library.containsPass(pass)
// 获取当前 App 有权访问的凭证列表
let passes = library.passes()
// 检查凭证库当前是否可用
guard PKPassLibrary.isPassLibraryAvailable() else { return }
常见踩坑与误区
切勿:将 StoreKit 用于实体商品结算
Apple Pay (PassKit) 专门用于实体商品、线下服务、捐赠以及符合条件的订阅/定期支付。StoreKit 则用于虚拟道具/商品、应用内功能开通和数字内容订阅。搞混框架会导致 App Review 被拒。
切勿:在多处硬编码 Merchant ID
// 错误写法:Merchant ID 分散在代码库各处
let request1 = PKPaymentRequest()
request1.merchantIdentifier = "merchant.com.example.app"
// ...其他地方:
let request2 = PKPaymentRequest()
request2.merchantIdentifier = "merchant.com.example.app" // 容易出现配置不一致
// 正确写法:统一集中管理配置
enum PaymentConfig {
static let merchantIdentifier = "merchant.com.example.app"
static let countryCode = "US"
static let currencyCode = "USD"
static let supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard, .amex]
}
审核检查清单
- [ ] 已在 Xcode 中启用 Apple Pay capability 并配置好 Developer 后台的 Merchant ID
- [ ] 已生成并安装 Payment Processing Certificate(支付处理证书)
- [ ] 在展示 Apple Pay 按钮前已调用
canMakePayments(usingNetworks:)进行检查 - [ ] 只要检测到用户卡片可用,Apple Pay 均处于突出且显眼的位置
<!-- truncated for translation batch; full body continues in source -->



