在 iOS 系统下,苹果对虚拟物品的交易是要抽成的,这个也限制了虚拟物品交易的支付渠道必须是 ApplePay 了,作为开发者,能做的也就是把 ApplePay 集成进我们的 App 吧。
一、配置环境
-
登录 Apple 开发者页面,申请一个商业标识符 MerchantID,并跟工程的 BundleIdentifier 绑定,具体步骤可以在网上找下。
-
在 Xcode 上配置 ApplePay 支持。
如果是 Xcode11 之下,在 Capabilities 中打开 ApplePay 选项开关即可;
如果是 Xcode11,则需要在 Signing & Capabilities 的左上角,点击
+ Capability手动添加一个 ApplePay 选项。 -
在第2步的 AppleyPay 选项中,如果没有显示出 MerchantId,则需要手动在
<工程名>.entitlements文件里的Merchant IDs下添加一个元素,填写在第1步中申请时填写的以merchant.开头的那个字符串。重启工程,就可以 ApplePay 选项中看到它了,显示为未找到的红色,不用管它。
二、开发
ApplePay 的 API 在 iOS10 系统前后有些区别,在 iOS10 之前是用 PKPaymentAuthorizationViewController 继承于 UIViewController,在 iOS10 之后用的是 PKPaymentAuthorizationController 继承于 NSObject。它们的 API 基本完全相同,本文就用 PKPaymentAuthorizationController 举例了,下面介绍一点主要的 API。
1、 权限判断
| API | 描述 |
|---|---|
| open class func canMakePayments() -> Bool | 判断设备是否支持 ApplePay |
| open class func canMakePayments(usingNetworks supportedNetworks: [PKPaymentNetwork]) -> Bool | 判断设备是否支持传入的网络的 ApplePay,如果 ApplePay 里没有支持的卡,或者没有卡也会返回 false |
2、 跳转钱包,设置银行卡,直接跳转到苹果的钱包应用,并唤起添加卡片页面
let wallet = PKPassLibrary()
wallet.openPaymentSetup()
3、设置商品信息,并唤起 ApplePay 支付页面
伪代码如下,注意要点都写在 注释 内
let request = PKPaymentRequest()
//国家
request.countryCode = "CN"
//币种
request.currencyCode = "CNY"
//支持的网络
var networks: [PKPaymentNetwork] = [.privateLabel]
if #available(iOS 11.2, *) {
networks.insert(.chinaUnionPay, at: 0)
}
request.supportedNetworks = networks
//商业标识符
request.merchantIdentifier = "merchant.xxxx"
//capability3DS 必须添加,在大陆 capabilityEMV 也必须添加,否则 didAuthorizePayment 方法不会调用
request.merchantCapabilities = [.capability3DS, .capabilityEMV, .capabilityCredit, .capabilityDebit]
//快递
let ship1 = PKShippingMethod(label: "顺丰", amount: .init(value: 10))
ship1.detail = "24小时送达"
ship1.identifier = "shunfeng"
let ship2 = PKShippingMethod(label: "韵达", amount: .init(value: 15))
ship2.detail = "隔天送达"
ship2.identifier = "yunda"
//快递列表
request.shippingMethods = [ship1, ship2]
//送货方式
request.shippingType = .shipping
//商品列表
let firstGoods = PKPaymentSummaryItem(label: "火锅", amount: .init(value: 0.00))
let secondGoods = PKPaymentSummaryItem(label: "青菜", amount: .init(value: 0.00))
paymentList = [firstGoods, secondGoods]
let list = showSummaryItems(with: ship1)
//添加商品列表,最后一个是总计
request.paymentSummaryItems = list
//商品附加信息,会被传到生成的 PKPaymentToken 中,可用于平台的校验
request.applicationData = "goodsId=123456".data(using: .utf8)
let payment = PKPaymentAuthorizationController(paymentRequest: request)
payment.delegate = self
payment.present(completion: nil)
4、回调处理
4.1 完成回调(取消支付、支付完成、失败都会调用)
func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) {
//隐藏支付页面
controller.dismiss(completion: nil)
}
4.2 认证回调
func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
//延时,模拟平台校验订单并且对接金融机构扣款
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
[unowned self] in
let ret = arc4random_uniform(4) % 2 == 0
if ret {
completion(.init(status: .success, errors: nil))
self.lbl.text = "支付成功"
} else {
completion(.init(status: .failure, errors: nil))
self.lbl.text = "支付失败"
}
}
}
4.3 切换送货方式回调
func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didSelectShippingMethod shippingMethod: PKShippingMethod, handler completion: @escaping (PKPaymentRequestShippingMethodUpdate) -> Void) {
let update = PKPaymentRequestShippingMethodUpdate(paymentSummaryItems: showSummaryItems(with: shippingMethod))
completion(update)
}
当然,上面的这些仅仅是 ApplePay 支付的一部分,整体的流程应该是这样的:

在认证回调里,拿到 PaymentToken 之后,需要服务端根据解析的订单信息从支付供应商那里扣款,并取得扣款结果,这个过程就是 demo 里的延时的过程。之后再根据扣款的结果处理下客户端的显示支付结果,就是那个 block 回调。
这个过程可以用不同的三方sdk来处理,可以在官网找到这些内容,根据他们的文档对接就好:

本文所有代码及工具方法在这里,欢迎 Star。
官方Demo在这里。
本文原地址为:www.shenhongbang.cc/ApplePayFir…。