Creating Payment Requests
Payment Requests
支付请求是PKPaymentRequest
类的实例。支付请求包含一系列描述用户的支付对象(为哪些东西付款)的概要项:可用的运送方式的列表,用户需要提供的运送信息的描述,关于商家和支付处理的信息。
Decide Whether the User Can Make Payments 判决用户是否有能力支付
在生成一个支付请求之前,通过调用PKPaymentAuthorizationViewController
类中的canMakePaymentsUsingNetworks:
方法判断用户是否能够使用支持的系统完成支付。使用canMakePayments
方法,检查设备的硬件和父类控制是否支持Apple Pay。
如果canMakePayments
返回NO,表示设备不支持Apple Pay。因此也不显示Apple Pay按钮,转到其他的支付方式。
如果canMakePayments
返回YES,但是canMakePaymentsUsingNetworks:
返回NO,表示设备支持Apple Pay,但是用户没有添加任何符合要求的支付系统的卡片。可选择性地去显示一个支付设置按钮,提示用户设置卡片。一旦用户点击了该按钮,初始化设置一个新卡的进程(例如:调用openPaymentSetup
方法)。
另外,一旦用户按下Apple Pay按钮,必须开始支付授权进程。在展示支付请求之前不能要求用户执行其他任何任务。例如,如果用户需要输入折扣码,必须在按下Apple Pay按钮之前请求该代码。
Bridging from Web-Based Interfaces 基于网络接口进行桥接
如果app使用网络接口购买物品和服务,必须在处理Apple Pay交易之前从网络接口移动该请求到本地iOS代码。列表3-1展示了需要处理web view的请求的步骤。
Listing 3-1Buying items from a web view
// Called when the web view tries to load "myShoppingApp:buyItem"
-(void)webView:(nonnull WKWebView *)webView
decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction
decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler {
// Get the URL for the selected link.
NSURL *URL = navigationAction.request.URL;
// If the scheme and resource specifier match those defined by your app,
// handle the payment in native iOS code.
if ([URL.scheme isEqualToString:@"myShoppingApp"] &&
[URL.resourceSpecifier isEqualToString:@"buyItem"]) {
// Create and present the payment request here.
// The web view ignores the link.
decisionHandler(WKNavigationActionPolicyCancel);
}
// Otherwise the web view loads the link.
decisionHandler(WKNavigationActionPolicyAllow);
}
Payment Requests Include Currency and Region Information 包括货币和地区信息的支付请求
在支付请求中所有的概要数值均使用相同的货币(指定使用PKPaymentRequest
类中的currencyCode
属性),均使用三个字母的ISO货币代码,例如USD。
支付请求的国家码表明在该国家发生购买操作或者在该国家购买将要被处理。使用两个字母的ISO国家码,例如US。
在支付请求中设置的商户ID(merchant ID)必须与app中的entitlement中的merchant IDs相匹配.
request.currencyCode = @"USD";
request.countryCode = @"US";
request.merchantIdentifier = @"merchant.com.example";
Payment Requests Have a List of Payment Summary Items支付请求有一个支付概要项的列表
展示在PKPaymentSummaryItem
类中的支付概要项,描述给用户的支付请求的不同部分。使用一个小部分的概要项- 典型地包含总和、任何折扣、运费、税金和最终的总和。如果没有任何其他额外的费用(例如:运费或税金),仅仅包含购物的总和。在app中提供逐项的消费细节。
每个概要项有一个标记和数值,展示在Listing 3-2。标记是用户可读的概要项总结的描述。该数值与支付数值是一致的。在支付请求中的所有数值均使用在支付请求中指定的货币。折扣或者优惠劵的数值,则设置为负数。
当支付被授权的时候,如果不知道某个实际的费用(例如:打车费),生成一个使用PKPaymentSummaryItemTypePending
类型的总和概要项并且值为0.0。该系统然后标记该费用为未决定的。
Listing 3-2Creating a payment summary item
// 12.75 subtotal
NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO];
self.subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"Subtotal" amount:subtotalAmount];
// 2.00 discount
NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithMantissa:200 exponent:-2 isNegative:YES];
self.discount = [PKPaymentSummaryItem summaryItemWithLabel:@"Discount" amount:discountAmount];
注意:
支付概要项使用NSDecimalNumber
类存储数量为以10为基的数。该类的实例可以通过明确地指定尾数和指数(展示在代码列表中)或者提供一个string
类型的数量并指定一个区域来创建。总是使用以10为基的数来进行金融计算,例如,确定5%折扣的数量。
即使IEEE的浮点类型数据例如float
和Double
显示起来非常方便,但不适合于金融计算。这些数据类型使用以2为基的数字表示出来,这意味着一些小数数值不能被精确地表示出来。例如:0.42很可能接近于0.419999无限循环。这类近似值会造成金融计算得到错误的结果。
在列表中最后的一个支付概要项是最终的总和。通过添加所有其他的概要项数值来计算总和数值。最终总和的显示不同于其他的概要项:使用公司的名称作为它的label
内容,使用所有其他的概要项的数值之和作为它的数值。使用paymentSummaryItems
属性添加支付概要项到支付请求。
// 10.75 grand total
NSDecimalNumber *totalAmount = [NSDecimalNumber zero];
// 计算总和
totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount];
totalAmount = [totalAmount decimalNumberByAdding:discountAmount];
self.total = [PKPaymentSummaryItem summaryItemWithLabel:@"My Company Name" amount:totalAmount];
self.summaryItems = @[self.subtotal, self.discount, self.total];
request.paymentSummaryItems = self.summaryItems;
A Shipping Method Is a Special Payment Summary Item 运送方式是一种特殊的支付概要项
为每个适用的运送方式创建一个PKShippingMethod
的实例。正如其他的支付概要项一样,运送方式有一个用户可读label
内容(例如“标准的运送”或者“次日运送”)和一个运费的数值。不像其他的概要项,运送方式也有detail属性-例如:“Arrives by July 29”或者“Ships in 24 hours”- 这说明了运送方式之间的不同。
为了在代理方法中区分运送方式,可使用identifier
属性。该属性仅仅被用于在自己的app中-框架处理它作为一个不透明的值,也不显示在UI界面中。当创建每个运送方式时,为它指定一个独一无二的标识。为了使调试容易些,使用摘要或者简短的string
值,例如“discount”,“standard”或者“next-day”。
一些运送方式不适用于所有的区域或者对不同的地址有不同的运费。当用户选择一个运送地址或者方式时可以更新这些信息,正如Your Delegate Updates Shipping Methods and Costs中描述的。
Indicating Your Support Payment Processing Mechanisms 指定支持的支付处理机制
通过用string
常量的数组填充supportNetworks
属性来指定支持何种支付系统。通过给merchantCapabilities
属性设定一个值来指定支持何种支付处理协议。必须支持3DS,支持EMV是可选的。
商家支付能力是位掩码,联合展示如下:
request.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkDiscover, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa];
// Supports 3DS only
request.merchantCapabilities = PKMerchantCapability3DS;
// Supports both 3DS and EMV
request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV;
Indicating What Shipping and billing Information Is Needed 指定哪些运送和账单信息是必需的
填充支付授权视图控制器的requiredBillingAddressFields和requiredShippingAddressFields
属性来指定哪些账单和运送信息是必需的。当展示该视图控制器时,它提示用户提供要求的账单和运送信息。这些区域的常量按照下面的方式联合设定这些属性的值:
request.requiredBillingAddressFields = PKAddressFieldEmail;
request.requiredBillingAddressFields = PKAddressFieldEmail | PKAddressFieldPostalAddress;
注意:
仅仅请求需要用来处理支付的账单和运送信息和传送商品或者服务。请求不必要的信息会增加不需要的复杂性。每个额外的步骤会增加用户简单地取消了该交易的可能性。
如果你有最新的账单和运送联系方式信息,可以在支付请求时设置这些内容。Apple Pay会默认使用这些信息;然而,用户仍然可以选择其他的联系方式信息作为支付授权处理的一部分。
PKContact *contact = [[PKContact alloc] init];
// 联系人姓名
NSPersonNameComponents *name = [[NSPersonNameComponents alloc] init];
name.givenName = @"John";
name.familyName = @"Appleseed";
contact.name = name;
// 联系人地址
CNMutablePostalAddress *address = [[CNMutablePostalAddress alloc] init];
address.street = @"1234 Laurel Street";
address.city = @"Atlanta";
address.state = @"GA";
address.postalCode = @"30303";
contact.postalAddress = address;
request.shippingContact = contact;
注意:
地址信息可以来自在iOS中的广泛的输入源。在使用它之前总是验证这些信息。
Storing Additional Information 存储额外的信息
为了存储每个app特定的支付请求的信息,例如一个购物车标识,使用applicationData
属性。该属性被对待作为一个系统提供的不透明的值。当用户授权支付请求之后一大把应用数据会显示在支付密钥中。