前不久Apple Pay开始了,大家做好接入的准备了吗?今天写了个demo,悲催的是开发者账号上设备满了,只能用模拟器给大家看了。。。疑问是:在开发Apple Pay的时候,Xcode 7无法 无证书真机调试吗?求解
0、 建新工程,忽略
由于想要使用Apple Pay,需要用到Apple颁布的merchant证书,所以要从申请APP ID开始:
1、在developer.apple创建App ID,如图:
根据工程的bundle id创建App ID,其他信息不多说,注意要在App Services栏,勾选 “Apple Pay”,如下图:
当创建完成后,查找到你的app id,结果如下图:
发现Apple Pay状态是黄色“configurable”,怎么激活呢,点击“Edit”,找到“Apple Pay”,点击对应的“Edit”,结果如图:
这就是让我们选择一个Merchant 证书,图中的两个是我创建的,那么大家可能是空的,如果是空的,这就需要去创建Merchant 证书了,然后继续这一步骤,为该App ID选择绑定一个Merchant证书。
创建Merchant证书方法:从左侧栏创建App IDs那找到Merchant IDs,点进去,新增一个ID!查找到该Merchant IDs,点击“Edit”,选择“YES”:
下面就是生产证书的步骤了,不多说,根据操作continue就行啦!!!最后我们会在本地得到一个.cer文件,双击即可。
2、配置Apple Pay到工程,如图:
如图操作,打开Apple Pay的开关,添加一个Merchant ID,如果没有你创建的,刷新一下,再选择即可。如果下面steps报红,问题可能是刚刚创建的Merchant ID并没有和App ID绑定,点击fix,一般都没问题了。
3、主要代码如下
import PassKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(type: UIButtonType.Custom)
btn.frame = CGRectMake(60, 100, 200, 50)
btn.center = self.view.center
btn.setBackgroundImage(UIImage(named: "ApplePayBTN_64pt__whiteLine_textLogo_"), forState: UIControlState.Normal)
btn.addTarget(self, action: "ApplePay", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(btn)
}
func ApplePay() {
if PKPaymentAuthorizationViewController.canMakePayments() {
print("support ApplePay")
let pkPayRequest = PKPaymentRequest()
let pkPayItem1 = PKPaymentSummaryItem(label: "Lamborghini LP650", amount: NSDecimalNumber(string: "1"))
let pkPayItem2 = PKPaymentSummaryItem(label: "La Ferrari", amount: NSDecimalNumber(string: "1"))
let pkPayItem3 = PKPaymentSummaryItem(label: "Shelby Super Car", amount: NSDecimalNumber(string: "1"))
let pkPayItem4 = PKPaymentSummaryItem(label: "Das Auto", amount: NSDecimalNumber(string: "3"), type: PKPaymentSummaryItemType.Final)
pkPayRequest.paymentSummaryItems = [pkPayItem1, pkPayItem2, pkPayItem3, pkPayItem4]
pkPayRequest.countryCode = "CN"
pkPayRequest.currencyCode = "CNY"
pkPayRequest.supportedNetworks = [PKPaymentNetworkVisa]
pkPayRequest.merchantIdentifier = "merchant.com.example.lbapplepaydemo"
pkPayRequest.merchantCapabilities = PKMerchantCapability.CapabilityCredit
pkPayRequest.requiredShippingAddressFields = PKAddressField.PostalAddress
pkPayRequest.shippingType = PKShippingType.Delivery
let method1 = PKShippingMethod(label: "顺丰快递", amount: NSDecimalNumber(string: "12"))
method1.identifier = "sf"
method1.detail = "全国包邮"
let method2 = PKShippingMethod(label: "圆通快递", amount: NSDecimalNumber(string: "10"))
method2.identifier = "yt"
method2.detail = "全国包邮"
pkPayRequest.shippingMethods = [method1, method2]
let pkVC = PKPaymentAuthorizationViewController(paymentRequest: pkPayRequest)
pkVC.delegate = self
self.presentViewController(pkVC, animated: true, completion: { () -> Void in
})
}
else {
print("该设备不支持支付")
}
}
}
extension ViewController: PKPaymentAuthorizationViewControllerDelegate {
func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, completion: (PKPaymentAuthorizationStatus) -> Void) {
print(payment.token)
let asyncSuccessful:Bool = false;
if asyncSuccessful {
completion(PKPaymentAuthorizationStatus.Success)
print("支付成功")
}
else {
completion(PKPaymentAuthorizationStatus.Failure)
print("支付失败")
}
}
func paymentAuthorizationViewControllerDidFinish(controller: PKPaymentAuthorizationViewController) {
controller .dismissViewControllerAnimated(true) { () -> Void in
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
如果手机上wallet已经有了用户的账单和配送信息,可以直接在支付请求中使用它们。但是尽管Apple Pay默认使用了这些信息,用户仍然可以在授权支付的过程中修改这些信息:
ABRecordRef record = ABPersonCreate();
CFErrorRef error;
BOOL success;
success = ABRecordSetValue(record, kABPersonFirstNameProperty, @"John", &error);
if (!success) { /* ... handle error ... */ }
success = ABRecordSetValue(record, kABPersonLastNameProperty, @"Appleseed", &error);
if (!success) { /* ... handle error ... */ }
ABMultiValueRef shippingAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
NSDictionary *addressDictionary = @{
(NSString *) kABPersonAddressStreetKey: @"1234 Laurel Street",
(NSString *) kABPersonAddressCityKey: @"Atlanta",
(NSString *) kABPersonAddressStateKey: @"GA",
(NSString *) kABPersonAddressZIPKey: @"30303"
};
ABMultiValueAddValueAndLabel(shippingAddress,
(__bridge CFDictionaryRef) addressDictionary,
kABOtherLabel,
nil);
success = ABRecordSetValue(record, kABPersonAddressProperty, shippingAddress, &error);
if (!success) { /* ... handle error ... */ }
request.shippingAddress = record;
CFRelease(shippingAddress);
CFRelease(record);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
额外信息怎么办?使用reques.applicationData来存储一些在你的应用中关于这次支付请求的唯一标识信息,比如一个购物车的标识符。在用户授权支付之后,这个属性的哈希值会出现在这次支付的token中。
到此已经完成了Apple Pay的接入 ^ _ ^
4、处理支付的其他代理详解:
支付授权过程是由支付授权view controller和它的代理协作完成的。支付授权view controller做了两件事情:它让用户选择支付请求所必需的账单和配送信息,还有让用户最终授权同意这次支付。当用户和view controller交互时,代理方法就会被调用,这样你的应用就可以不断地更新显示的信息–例如在配送地址更改后更新配送费用。用户最终授权支付请求之后代理方法同样也会被调用。
注意:在实现这些方法时注意,这些方法可能会被多次调用,而它们被调用的顺序取决于用户的行为的顺序。
当用户提供配送信息之后,授权view controller 会调用paymentAuthorizationViewController:didSelectShippingAddress:completion: 和 paymentAuthorizationViewController:didSelectShippingMethod:completion:这两个代理方法。在这两个方法中根据最新信息来更新支付请求。
func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController, didSelectShippingMethod shippingMethod: PKShippingMethod, completion: (PKPaymentAuthorizationStatus, [PKPaymentSummaryItem]) -> Void) {
print(shippingMethod.detail)
completion(PKPaymentAuthorizationStatus.Success, self.summaryItems)
}
func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController, didSelectShippingAddress address: ABRecord, completion: (PKPaymentAuthorizationStatus, [PKShippingMethod], [PKPaymentSummaryItem]) -> Void) {
print(address)
completion(PKPaymentAuthorizationStatus.Success, self.shippingMethods,self.summaryItems)
}
当支付被授权后,支付token会被创建
当用户最终授权了一个支付请求,框架会通过与苹果服务器和嵌入在设备中的一个安全模块进行通信,生成一个支付token。然后你在paymentAuthorizationViewController:didAuthorizePayment:completion:方法中将这个token和其它一些你需要用来处理这次购买的信息–例如配送地址和购物车标识–发送给你的服务器。这个过程是这样的:
框架发送支付请求给安全模块,只有安全模块可以访问存储在设备上的标记化的卡信息。
安全模块把特定的卡和商家等支付数据加密,以保证只有苹果可以读取,然后发送给框架。框架会将这些数据发送给苹果。
苹果服务器再次加密这些支付数据,以保证只有商家可以读取。然后服务器对它进行签名,生成支付token,然后发送给设备。
框架调用相应的代理方法并传入这个token,然后你的代理方法传送token给你的服务器。
至于你的服务器采取的行为要取决于你是自己处理这次支付或者你是和其它支付平台合作来进行支付处理。不管怎样,你的服务器处理这个订单然后传送一个状态信息给设备,代理方法会把这个状态信息传送给completion块,像在“Processing a Payment”中讨论过的。
func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, completion: (PKPaymentAuthorizationStatus) -> Void) {
print(payment.token)
let asyncSuccessful:Bool = false;
/**
将支付令牌payment上传服务器端,验证签名,获取token?
*/
let error:NSError
let addressMultiValue = ABRecordCopyValue(payment.billingContact, kABPersonAddressProperty) as! ABMultiValue
let addressDictionary = ABMultiValueCopyValueAtIndex(addressMultiValue, 0) as! AnyObject
do {
let json = try NSJSONSerialization.dataWithJSONObject(addressDictionary, options: NSJSONWritingOptions.PrettyPrinted)
}
catch {
}
// 根据返回,判断成功与否
if asyncSuccessful {
completion(PKPaymentAuthorizationStatus.Success)
print("支付成功")
}
else {
completion(PKPaymentAuthorizationStatus.Failure)
print("支付失败")
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
5、 支付处理
处理一个支付请求涉及以下几个步骤:
把支付信息,以及支付流程+所需的其他信息,一起发送给你的服务器
验证支付数据的哈希表和签名
为加密过的支付数据解码
向支付处理系统提交支付数据
向订单追踪系统提交订单
处理支付请求时,你有两个选择:你既可以利用支付平台处理支付请求,也可以自己实现支付请求处理流程。一个常用的支付平台可以完成上述大部分操.
Demo 地址:https://github.com/jakajacky/ApplePayDemo.git