Authorizing Payments
支付授权处理是支付授权视图控制器和它的代理之间的协力合作的结果。支付授权视图控制器做两件事:让用户选择支付请求中所需要的账单和运送信息,让用户去授权支付。当用户和视图控制器交互时调用代理的方法以便app可以更新展示的信息-例如:当一个运送地址被选择时更新运送价格。在用户授权支付请求之后调用该代理。
注意:
当实现代理方法时,记得它们会被调用很多次并且它们被调用的规则取决于用户的动作顺序。
所有在授权处理期间调用的代理方法均传送一个完成的block
作为它们的参数之一。在它调用其他代理方法之前,支付授权视图控制器等待代理完成响应一个方法(通过调用完成block
)。paymentAuthorizationViewControllerDidFinish:
方法是唯一的例外。它没有取到完成block
,但是它在任何时候均可被调用。
完成 block
取到一个论证,该论证可以指定基于可用信息的交易的当前授权状态。如果该交易没有任何问题,传送该值PKPaymentAuthorizationStatusSuccess
;否则,传送一个值来标识错误。
为了创建一个PKPaymentAuthorizationViewController
类的实例,传送支付请求给视图控制器的初始化。设置该视图控制器的代理,然后显示它。
PKPaymentAuthorizationViewController *viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
if (!viewController) { /* ... Handle error ... */ }
viewController.delegate = self;
[self presentViewController:viewController animated:YES completion:nil];
当用户与视图控制器交互时,视图控制器调用它的代理方法。
注意:
在Xcode 7.0或者以后,可以在模拟器上测试支付授权视图控制器。它提供了所有支持的支付系统的模拟卡片并以简单的文本形式返回虚拟的支付数据。在设备上,该数据使用商户标识加密并必须在自己的服务器上或者在支付处理时解密。
虽然模拟器提供一个快捷而且方便的方式测试自己的代码,仍然需要在真实的物理设备上完全地测试Apple Pay。
如果使用 Xcode的早期版本,仅仅可以在设备上测试Apple Pay。
Your Delegate Updates Shipping Methods 代理更新运送方式和费用
当用户提供运送信息时,授权视图控制器调用代理的paymentAuthorizationViewController:didSelectShippingContact:completion:
方法和paymentAuthorizationViewController:didSelectShippingMethod:completion:
方法。使用这些方法来更新基于这些新信息的支付请求。
- (void) paymentAuthorizationViewController: (PKPaymentAuthorizationViewController *)controller
didSelectShippingContact:(CNContact *)contact
completion:(void (^) (PKPaymentAuthorizationStatus, NSArray *, NSArray *))completion
{
self.selectedContact = contact;
[self updateShippingCost];
NSArray *shippingMethods = [self shippingMethodsForContact:contact];
completion(PKPaymentAuthorizationStatusSuccess, shippingMethods, self.summaryItems);
}
- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didSelectShippingMethod:(PKShippingMethod *)shippingMethod
completion:(void (^)(PKPaymentAuthorizationStatus, NSArray *))completion
{
self.selectedShippingMethod = shippingMethod;
[self updateShippingCost];
completion(PKPaymentAuthorizationStatusSuccess, self.summaryItems);
}
注意:
为了维护隐私,paymentAuthorizationViewController:didSelectShippingContact:completion:
方法中提及的运送信息是匿名的。返回的联系方式包含足够的信息用以计算运费,不展现用户的敏感信息。直到用户批准了该支付之后,才能获取到用户的全部运送信息,否则不能获取到。另外,联系方式中的数据可以根据不同的国家而改变,并可以一次又一次地改变。保证以合适的方式测试app。
A Payment Token Is Created When a Payment Is Authorized 当支付被授权时生成一个支付密钥
当用户授权支付请求时,框架通过Apple 服务器和安全元件联合生成一个支付密钥。可以通过paymentAuthorizationViewController:didAuthorizePayment:completion:
代理方法传送该支付密钥给自己的服务器,与其它需要的信息一起处理购买。例如:运送地址和购物车标识。过程如下:
- 1.框架发送支付请求给安全元件。只有安全元件可以使用tokenized标记化的特定设备的支付卡号。
- 2.安全元件将含有特定卡和商户的支付数据 放在一起,加密它使得只有Apple 可以读取它,并发送它给框架。框架然后发送支付数据给Apple 服务器。
- 3.Apple 服务器使用Merchant Identifier certificate商户标识证书解密支付数据。该密钥仅仅自己和那些已分享商户标识证书给他们的人可读。然后服务器写下该支付密钥,并返回它给设备。
- 4.框架通过调用
paymentAuthorizationViewController:didAuthorizePayment:completion:方法传送该密钥给代理。代理传送该密钥给自己的服务器。
在自己服务器上的行为改变取决于是否处理自己的支付或者对一个支付平台有效。在两种情况下,服务器处理订单并传送一个状态返回给设备,代理可传送给它的完成处理者,具体描述在Processing a Payment。
- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didAuthorizePayment:(PKPayment *)payment
completion:(void (^)(PKPaymentAuthorizationStatus))completion
{
NSError *error;
ABMultiValueRef addressMultiValue = ABRecordCopyValue(payment.billingAddress, kABPersonAddressProperty);
NSDictionary *addressDictionary = (__bridge_transfer NSDictionary *) ABMultiValueCopyValueAtIndex(addressMultiValue, 0);
NSData *json = [NSJSONSerialization dataWithJSONObject:addressDictionary options:NSJSONWritingPrettyPrinted error: &error];
// ... Send payment token, shipping and billing address, and order information to your server ...
PKPaymentAuthorizationStatus status; // From your server
completion(status);
}
Your Delegate Dismisses the Payment Authorization View Controller代理dismiss支付授权视图控制器
当框架显示交易的状态之后,授权视图控制器调用代理的paymentAuthorizationViewControllerDidFinish:
方法。在实施阶段,dismiss
授权视图控制器并且显示自己app特定的订单确认页面。
- (void) paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller
{
[controller dismissViewControllerAnimated:YES completion:nil];
}