欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

ApplePay完整添加流程

程序员文章站 2022-03-16 16:45:04
// // AppleTool.h // ApplePayTool // // Created by liangkun on 16/8/1. // Copyright ?...

//

// AppleTool.h

// ApplePayTool

//

// Created by liangkun on 16/8/1.

// Copyright ? 2016年 liangkun. All rights reserved.

//

#import

#import

#import

@interface AppleTool : NSObject

/**

* 用户的姓名

*/

@property(nonatomic,strong) NSString *userName;

/**

* 商品的价格

*/

@property(nonatomic,assign) unsigned long long price;

/**

* 商品的折扣(不可为零)

*/

@property(nonatomic,assign) unsigned long long disCount;

/**

*

*

* @param PayAbout 支付相关的其它内容不需要其它相关内容可直接调用init方法

*

* @return

*/

+(instancetype)initWith:(NSObject *)PayAbout;

/**

*

*

* @return 当前设备是否支持ApplePay服务

*/

+ (BOOL)isUserCanMakePayment;

/**

*

*

* @return 获取要展示的ApplePay支付界面

*/

- (PKPaymentAuthorizationViewController*)getAuthorzationViewController;

- (void)verifyApplePayWith:(NSData *)paymentTocken Result:(void(^)(BOOL success))result;

@end

//

// AppleTool.m

// ApplePayTool

//

// Created by liangkun on 16/8/1.

// Copyright ? 2016年 liangkun. All rights reserved.

//

//extern NSString * const PKEncryptionSchemeECC_V2 NS_AVAILABLE_IOS(9_0);

//

//extern NSString * const PKPaymentNetworkAmex NS_AVAILABLE(NA, 8_0);

//extern NSString * const PKPaymentNetworkChinaUnionPay NS_AVAILABLE(NA, 9_2);

//extern NSString * const PKPaymentNetworkDiscover NS_AVAILABLE(NA, 9_0);

//extern NSString * const PKPaymentNetworkInterac NS_AVAILABLE(NA, 9_2);

//extern NSString * const PKPaymentNetworkMasterCard NS_AVAILABLE(NA, 8_0);

//extern NSString * const PKPaymentNetworkPrivateLabel NS_AVAILABLE(NA, 9_0);

//extern NSString * const PKPaymentNetworkVisa NS_AVAILABLE(NA, 8_0);

//PKMerchantCapability3DS = 1UL << 0, // Merchant supports 3DS

//PKMerchantCapabilityEMV = 1UL << 1, // Merchant supports EMV

//PKMerchantCapabilityCredit NS_ENUM_AVAILABLE_IOS(9_0) = 1UL << 2, // Merchant supports credit

//PKMerchantCapabilityDebit NS_ENUM_AVAILABLE_IOS(9_0) = 1UL << 3 // Merchant supports debit

#import "AppleTool.h"

@interface AppleTool()

@property (nonatomic, strong) NSArray *SupportnetWorks;

@end

@implementation AppleTool

- (instancetype)init

{

if (self = [super init]) {

}

return self;

}

+ (instancetype)initWith:(NSObject *)PayAbout

{

AppleTool *tool = [[AppleTool alloc]init];

if (tool) {

}

return tool;

}

/**

* 检测当前的硬件和家长控制

*

* @return 硬件是否支持和是否有家长控制等原因

*/

+ (BOOL)isUserCanMakePayment

{

BOOL canMakePayment = [PKPaymentAuthorizationViewController canMakePayments];

return canMakePayment;

}

/**

* 当前的用户是否为请求网络添加卡

*

* @return 用户是否添加银行卡为这个手机

*/

- (BOOL)isUserCanMakePaymentUseingNetWork

{

BOOL canMakePaymetUserNet = [PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:self.SupportnetWorks];

return canMakePaymetUserNet;

}

- (PKPaymentRequest *)createPaymentRequest

{

PKPaymentRequest *request = [[PKPaymentRequest alloc]init];

request.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkDiscover, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay];

request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV|PKMerchantCapabilityCredit|PKMerchantCapabilityDebit;

request.countryCode = @"CN";

request.currencyCode = @"CNY";

request.merchantIdentifier = @"商户在开发者帐号中申请的ID";

/**

* 配置请求的联系人

*/

request.shippingContact = [self getUserContact];

NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:self.price exponent:0 isNegative:NO];

PKPaymentSummaryItem *subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"小计" amount:subtotalAmount];

// 2.00 discount

// 打折

if (self.disCount > 0) {

NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithMantissa:self.disCount exponent:0 isNegative:YES];

PKPaymentSummaryItem *discount = [PKPaymentSummaryItem summaryItemWithLabel:@"打折" amount:discountAmount];

NSDecimalNumber *totalAmount = [NSDecimalNumber zero];

totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount];

PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"有妖气" amount:totalAmount];

NSArray *summaryItems = @[subtotal,discount,total];

request.paymentSummaryItems = summaryItems;

} else

{

NSDecimalNumber *totalAmount = [NSDecimalNumber zero];

totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount];

PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"有妖气" amount:totalAmount];

NSArray *summaryItems = @[subtotal,total];

request.paymentSummaryItems = summaryItems;

}

//如果需要用户的地址信息打开此行代码

// request.requiredShippingAddressFields = PKAddressFieldAll;

return request;

}

-(PKContact*)getUserContact

{

PKContact *contact = [[PKContact alloc] init];

//消费着的名字

NSPersonNameComponents *name = [[NSPersonNameComponents alloc] init];

name.nickname = self.userName;// 用户名

contact.name = name;

return contact;

}

- (PKPaymentAuthorizationViewController*)getAuthorzationViewController

{

PKPaymentAuthorizationViewController *viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:[self createPaymentRequest]];

return viewController;

}

- (void)verifyApplePayWith:(NSData *)paymentTocken Result:(void (^)(BOOL))result

{

/**

* 保存当前的数据到云上

*/

[self savePaymentDataToiCloudWith:paymentTocken];

NSString *encodeStr = [paymentTocken base64EncodedStringWithOptions: NSDataBase64EncodingEndLineWithCarriageReturn];

//发送加密数据到服务器用来划账

}

//保存要验证的数据到云上

- (void)savePaymentDataToiCloudWith:(NSData*)paymentTocken

{

NSUbiquitousKeyValueStore *storage = [NSUbiquitousKeyValueStore defaultStore];

[storage setObject:@[paymentTocken] forKey:@"applePayMentTocken"];

[storage synchronize];

}

//- (void)clearPaymentDataIniCloud:()

@end

在ViewController中调用

AppleTool *applePayTool = [[AppleTool alloc]init];

applePayTool.price = (unsigned long long)100;

applePayTool.disCount = 12;

applePayTool.userName = @"jack Jhon";

PKPaymentAuthorizationViewController *viewController = [applePayTool getAuthorzationViewController];

self.viewController = viewController;

if (!viewController)

{

//处理创建支付View失败的问题

}else

{

viewController.delegate = self;

[self presentViewController:viewController animated:YES completion:nil];

}

}

About Apple Pay

IMPORTANT

This documentation contains preliminary information about an API or technology in development. This information is subject to change, and software implemented according to this documentation should be tested with final operating system software.

这就是一个开发知道以最好的真机调试为准

Apple Pay is a mobile payment technology that lets users give you their payment information for real-world goods and services in a way that is both convenient and secure.

苹果支付是移动支付技术它让用户给你他们的为了真实世界物品和服务的付款信息以一种方便又安全的方法。

For digital goods and services delivered within the app, see In-App Purchase Programming Guide.

对于电子物品和服务在app内的传送,参见内购编程直到

image: ../Art/payment_intro_2x.png

Working with Apple Pay

Apps that use Apple Pay need to enable the Apple Pay capabilities in Xcode. You also register a merchant identifier and set up cryptographic keys, which are used to securely send payment data to your server.

***使用Apple Pay 的app需要去在Xcode中打开Apple Pay的能力***。你也注册一个***

商人ID和设置密码 钥匙,密码钥匙被用来安全的发送支付数据到你的服务器***,

To initiate a payment, your app creates a payment request. This request includes the subtotal for the services and goods purchased, as well as any additional charges for tax, shipping, or discounts. Pass this request to a payment authorization view controller, which displays the request to the user and prompts for any needed information, such as a shipping or billing address. Your delegate is called to update the request as the user interacts with the view controller.

去初始化一个支付,你的app创建一个支付请求。这个请求包含服务和购买的商品的小计,以及安和额外的税务,运费,或打折等。传送这个请求到一个支付授权view 控制器,控制器展示请求给用户提示任何需要的信息,比如航运或计费地址。****你的代理被调用去更新请求随着用户和这个View控制器交互****。

As soon as the user authorizes the payment, Apple Pay encrypts payment information to prevent an unauthorized third party from accessing it. On the device, Apple Pay sends the payment request to the Secure Element, which is a dedicated chip on the user’s device. The Secure Element adds the payment data for the specified card and merchant, creating an encrypted payment token. It then passes this token to Apple’s servers, where it is reencrypted using your Merchant Identifier certificate. Finally, the servers pass the token back to your app for processing.

一旦用户授权付款Apple Pay 加密支付信息去防止未授权的第三方信息去访问它。在设备上。Apple Pay 发送这个支付请求到安全元素,就是一个在用户设备上的专用芯片。这个安全元素添加支付数据到明确的卡片和商户,创建一个加密支付tocken.它然后发送这个tocken 到苹果的服务器,这里token 被使用你的商户ID 证书再次加密。最后最后这个服务器传送这个tocken 到你的app去处理。

The payment token is never accessed or stored on Apple’s servers. The servers simply reencrypt the token using your certificate. This process lets your app securely encrypt the payment information without it having to distribute your Merchant Identifier certificate as part of the app.

这个支付tocken 在苹果的服务器永远不被访问或存储。这个服务器简单的使用你的证书再次加密这个tocken。这个过程让你的app安全加密支付信息而不用去分布你的商户ID证书作为你的app的一部分。

For more information about Apple Pay’s security, see iOS Security Guide.

更多关于Apple Pay的安全信息,参见iOS Security Guide.

In most cases, your app passes the encrypted payment token to a third-party payment solution provider to decrypt and process the payment. However, if your team has an existing payment infrastructure, you can decrypt and process the payment on your own server.

在多数情况,你的app传送这个加密支付token到一个三方支付解决提供者去揭秘和处理支付,如果你的团队有存在支付基础设施,你能揭秘和处理支付在你自己的服务器。

For information about payment solution providers that support Apple Pay, see developer.apple.com/apple-pay/.

更多支持Apple Pay 关于支付解决提供者信息,参见developer.apple.com/apple-pay/.

Testing Apple Pay Transactions

测试Apple Pay 交易

Use the Apple Pay Sandbox environment to test your transactions with test payment cards.

使用Apple Pay Sandbox 环境去使用你的支付卡去测试你的交易。

In iTunes Connect, create a test account. This account works for both App Store and Apple Pay testing.

在 iTunes Connect,创建一个测试账号。这个测试账号在App Store 和Apple Pay 测试 都有用。

On a valid test device, log into iCloud using the test account.

在一个可用测试设备,使用测试账号登录到iCloud.

In the Wallet app, add a new card using manual entry.

在Wallet app,使用手工输入添加一个新卡。

Logging in and out of your iCloud account removes your cards. Test cards can only be used in the Sandbox environment. Additionally, the Sandbox environment tests only the connection between your app and the test card network. It does not test the connection between your app and your payment solution provider.

登录和退出你的iCloud账号移除你的卡。测试卡只能被用来Sandbox 环境。这个Sandbox环境测试仅仅在你的app和测试卡网络之间连接。它不测试在你的app和你支付解决提供者之间的连接。

Configuring Your Environment

配置你的环境

A merchant ID identifies you to Apple Pay as being able to accept payments. The public key and certificate associated with your merchant ID is used as part of the payment process to encrypt payment information. Before your app can use Apple Pay, you need to register a merchant ID and configure its certificate.

一个商户ID 标记你对Apple Pay 作为能去接受支付。这个公用key和与 你的商户ID 相关的证书 被用来作为支付处理的一部分去加密支付信息。在你的app能使用Apple Pay之前,你需要去注册一个商务ID和配置她的证书。

To register a merchant ID

************************************************注册商户ID*******************************************

去注册一个商务ID

In Member Center, select Certificates, Identifiers & Profiles.

Under Identifiers, select Merchant IDs.

在 会员中心选择 Certificates,Identifiers & Profiles.

在 Identifiers 下面,选择Merchant IDs.

Click the Add button (+) in the upper-right corner.

点击右上角的加号。

Enter a description and identifier, and click Continue.

输入一个描述和ID,点击Continue.

Review the settings, and click Register.

检查设置点击注册。

Click Done.

点击Done。

**********************************************配置商户证书****************************************

To configure a certificate for your merchant ID

为你的商户ID去配置一个证书

In Member Center, select Certificates, Identifiers & Profiles.

在会员中心,选择Certificates,Identifiers & Profiles.

Under Identifiers, select Merchant IDs.

在Identifiers下面,选择Merchant IDs.

Select the merchant ID from the list, and click Edit.

从列表中选择 商户ID,点击编辑。

Click Create Certificate, follow the instructions to obtain or generate your certificate signing request (CSR), and click Continue.

点击创建证书,按照执导去获取你的证书签名请求(CSR),点击继续。

Click Choose File, select your CSR, and click Generate.

Download the certificate by clicking Download, and click Done.

点击 Choose File,选择 你的CSR,点击 Generate.

通过点击下载下载证书,和点击完成。

If you see a warning in Keychain Access that the certificate was signed by an unknown authority or that it has an invalid issuer, make sure you have the WWDR intermediate certificate - G2 and the Apple Root CA - G2 installed in your keychain. You can download them from apple.com/certificateauthority.

如果你看到一个警告证书被一个未知机构或它有一个不可用的发行者,确保你有WWDR中级证书-G2和苹果根CA-G2 安装在你的钥匙串。你下载他们从apple.com/certificateauthority.

To enable Apple Pay for your app in Xcode, open the Capabilities pane. Select the switch in the Apple Pay row, and then select the merchant IDs you want the app to use.

去可用Apple Pay 为你的app 在Xcode,打开 Capabilities 窗口。选择Apple Pay 行的开关,然后选择你想让App 去使用的商户ID。

image: ../Art/enable_apple_pay.png

NOTE

When troubleshooting, it is sometimes helpful to enable Apple Pay manually. Follow these steps to manually enable Apple Pay:

遵守如下步骤去手工可用Apple Pay:

In Member Center, select Certificates, Identifiers & Profiles.

会员中心,选Certificates,Identifiers &Profiles.

Under Identifiers, select App IDs.

在Identifiers,选择 App IDs.

Select the app ID from the list, and click Edit.

从列表中选择app ID,点击编辑。

Select Apple Pay, then click Edit.

选择Apple Pay,然后点击编辑。

Select the merchant IDs you want to use, and click Continue.

选择你想用的商户ID。点击继续

Review the settings, and click Assign.

检查设置点击Assign.

Click Done.

点击Done.

Creating Payment Requests

创建支付请求

Payment requests are instances of the PKPaymentRequest class. A payment request consists of a list of summary items that describe to the user what is being paid for, a list of available shipping methods, a description of what shipping information the user needs to provide, and information about the merchant and the payment processor.

*****支付请求是SKPaymentRequest类的实例*****。一个支付请求由一个描述给用户什么被支付的项目的列表组成,可用运输方法的列表,描述用户需要提供什么运输信息,关于商户和支付处理器的信息*****。

Decide Whether the User Can Make Payments

决定是否用户能产生支付

Before creating a payment request, determine whether the user will be able to make payments using a network that you support by calling the canMakePaymentsUsingNetworks: method of the PKPaymentAuthorizationViewController class. To check whether Apple Pay is supported by this device’s hardware and parental controls, use the canMakePayments method.

在创建一个支付请求之前,使用你支持的网络调用PKPaymentAuthorizationViewController 类的方法 canMakePayments UsingNetworks 方法决定是否用户将能够去产生支付。去检查是否Apple Pay 被这个设备的硬件支持和家长控制,使用canMakePayments 方法。

NOTE

The PKPaymentAuthorizationController class performs the same role as the PKPaymentAuthorizationViewController class, but it does not depend on the UIKit framework. This means that the authorization controller can be used in places where a view controller cannot (for example, in watchOS apps or in Intents extensions).

这个PKPaymentAuthorizationController 类执行相同的角色和PKPaymentAuthorizationViewController类,但是它不依赖UIKit框架。这意外着授权控制器能被使用在view 控制器不能用的地方(比如在 watchOS app或内容的扩展上)

If canMakePayments returns NO, the device does not support Apple Pay. Do not display the Apple Pay button. Instead, fall back to another method of payment.

如果canMakePayments 返回NO,这个设备不支持Apple Pay,不要展示Apple Pay 按钮,使用支付的其他方法。

If canMakePayments returns YES but canMakePaymentsUsingNetworks: returns NO, the device supports Apple Pay, but the user has not added a card for any of the requested networks. You can, optionally, display a payment setup button, prompting the user to set up his or her card. As soon as the user taps this button, initiate the process of setting up a new card (for example, by calling the openPaymentSetup method).

如果 canMakePayments 返回YES 但是 canMakePaymentsUsingNetworks:返回NO,这个设备支持Apple Pay,但是用户还没有添加一个卡为任何的请求网络。你能选择性的,展示一个支付设置按钮,催促用户去设置他或她的卡。初始化设置新卡的进程(比如通过调用openPaymentSetup 方法)。

Otherwise, as soon as the user presses the Apple Pay button, you must begin the payment authorization process. Do not ask the user to perform any other tasks before presenting the payment request. For example, if the user needs to enter a discount code, you must ask for the code before he or she presses the Apple Pay button.

否则,随着用户点击了Apple Pay 按钮,你必须开始支付授权进程。不要让用户去执行其他任务在展示支付请求之前。比如,如果用户需要去输入一个折扣代码,你必须去调用这个代码在她点击Apple Pay 按钮之前。

NOTE

注意

To create an Apple Pay–branded button for initiating payment request on iOS 8.3 or later, use the PKPaymentButton class. For iOS 8.2 or earlier, use the resources described in the Apple Pay Identity Guidelines.

去创建一个Apple Pay-品牌 按钮为初始化支付请求在iOS8.3或以后,使用PKPaymentButton 类。对iOS8.2或之前,使用在Apple Pay Identity Guidelines 中的资源描述。

For additional guidelines on using Apple Pay buttons and payment marks, see Apple Pay in iOS Human Interface Guidelines.

在使用Apple Pay 按钮和支付标记的附件指导,参见Apple Pay 在iOS Human Interface Guidelines.

Bridging from Web-Based Interfaces

从基于网页基础的接口桥接

If your app uses a web-based interface for purchasing goods and services, you must move the request from the web interface to native iOS code before processing an Apple Pay transaction. Listing 3-1 shows the steps needed to process requests from a web view.

如果你的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"

调用这个方法当web view尝试去加载“”

-(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

支付请求包括货币和区域信息

All of the summary amounts in a payment request use the same currency, which is specified using the currencyCode property of PKPaymentRequest. Use a three-character ISO currency code, such as USD.

在一个支付请求中的所有的总结金额使用相同的货币,这是明确使用PKPaymentRequest的currencyCode属性。使用一个三字节iOS货币代码。比如USD。

The payment request’s country code indicates the country where the purchase took place or where the purchase will be processed. Use a two-character ISO country code, such as US.

这个支付请求的国家代码表示购买发生的国家或这个购买将被进行的地方。使用两子节的ISO国际代码,比如US。

The merchant ID you set in a payment request must match one of the merchant IDs in your app’s entitlement.

这个你在支付请求中设置的商户ID必须匹配你的app的entitilement中的商户ID中的一个。

request.currencyCode = @"USD";

request.countryCode = @"US";

request.merchantIdentifier = @“merchant.com.example";

Payment Requests Have a List of Payment Summary Items

支付请求有一个支付总结项目列表。

Payment summary items, represented by the PKPaymentSummaryItem class, describe the different parts of the payment request to the user. Use a small number of summary items—typically the subtotal, any discount, the shipping, the tax, and the grand total. If you do not have any additional fees (for example, shipping or tax), just use the purchase’s total. Provide granular details of the item-by-item costs elsewhere in your app.

***支付总结项目,通过PKPaymentSummaryItem Class呈现,描述支付请求的不同部分给用户。使用一个小数量的总结项目-特别是小计,任何折扣,航运,税务,总和。如果你没有任何附加费(比如,运费或税务),只要使用购买的总和。 提供项目花费的具体细节在你的app的其它地方*****。

Each summary item has a label and an amount, as shown in Listing 3-2. The label is a user-readable description of what the item summarizes. The amount is the corresponding payment amount. All of the amounts in a payment request use the currency specified in the payment request. For a discount or a coupon, set the amount to a negative number.

每个项目归纳有一个标签和一个数量,就像表3-2列表中的的那样。这个标签是一个用户可读关于项目归纳的描述。这个数量是对呀的支付数量。所有的在支付请求中的钱数使用在付款请求中使用的货币。对于打折和优惠劵,把钱数设置到一个更小的数量。

If you do not know the actual cost when the payment is authorized (for example, a taxi fare), make a subtotal summary item using the PKPaymentSummaryItemTypePending type and a 0.0 amount. The system then marks the cost as pending.

如果你不知道真实的花费当支付被授权的时候(比如,出租车费用),使用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];

NOTE

Payment summary items use the NSDecimalNumber class to store the amount as a base-10 quantity. Instances of this class can be created by explicitly specifying the mantissa and exponent (as shown in the code listings) or by providing the quantity as string and specifying a locale. Always use base-10 numbers for financial calculations—for example, to determine the amount of a 5% discount.

支付总结项目使用NSDecimalNumber类去存储钱数作为以10为基础的数量。这个类的实例能被显示的指定尾数和指数创建(就像代码展示列表中的那样)或通过提供数量作为字符串和提供区域设置。总是使用10基数数组为财金计算-比如去决定%5的打折是多少。

Although they may appear to be more convenient, IEEE floating point data types such as float and Double are not suitable for financial calculations. These data types use a base-2 representation of numbers, which means that some decimal numbers can’t be represented exactly—for example, 0.42 must be approximated as 0.41999 repeating. Such approximations can cause financial calculations to return incorrect results.

经管他们可能表现更加便利,IEEE浮点数据类型比如作为float 和 Double不适合财金计算。哪些数据类型使用2基数数字的展示,这就意外着一些十进制数字不能被准确的展示-比如,0.42一定是约等于0.41999后重复。这样的约等能造成财金计算返回错误结果。

The last payment summary item in the list is the grand total. Calculate the grand total amount by adding the amounts of all the other summary items. The grand total is displayed differently from the other summary items: Use your company’s name as its label, and use the total of all the other summary items’ amounts as its amount. Add the payment summary items to the payment request using the paymentSummaryItems property.

在列表中的最后支付总结是全部的。通过加和其它总结项目的钱数计算总金额。这个总金额被展示不同于其它总结项目:使用你的公司的名字作为它的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

一个运输方法是一个 Special Payment Summary Item

Create an instance of PKShippingMethod for each available shipping method. Just like other payment summary items, shipping methods have a user-readable label such as Standard Shipping or Next Day Shipping, and an amount that is the shipping cost. Unlike other summary items, shipping methods also have a detail property—such as “Arrives by July 29” or “Ships in 24 hours”—that explains the difference between shipping methods.

创建一个PKShippingMethod的实例为每个可用的运输方法。就像其它支付总结项目,运输方法有一个 用户-可读标签比如 Standard Shipping 或Next Day Shipping, 和一个运输花费。不想其它总结项目,运输方法也有一个 详细属性-比如“Arrives by July 29”或“Ships in 24 hours”-解释运输方法之间的不同。

To distinguish shipping methods in your delegate methods, use the identifier property. This property is used only by your app—the framework treats it as an opaque value and it doesn’t appear in the UI. Assign a unique identifier for each shipping method when you create it. For ease of debugging, use a brief or abbreviated string, such as “discount,” “standard,” or “next-day.”

去在你的代理方法中区分运输方法,使用identifier 属性,这个属性只被你的app使用-这个框架对待它作为一个不透明的值和不展示它在UI。赋值一个非透明identifier为没一个运输方法当你创建它。对于调试场景,使用一个简单或字符串缩写,比如“打折”,“标准”,或“下一天”。

Some shipping methods aren’t available in all areas or have different costs for different addresses. You can update this information when the user selects a shipping address or method, as described in Your Delegate Updates Shipping Methods and Costs.

一些运输方法不是可用的在所有的区域或有不同的花费为不同的地址。你能更新这个信息当用户选择一个运输地址和方法,就像描述在Your Delegate Updates Shipping Methods 和花费。

Indicating Your Supported Payment Processing Mechanisms

标示你的被支持的支付处理机制

Indicate which payment networks you support by populating the supportedNetworks property with an array of string constants. Indicate which payment processing protocols you support by setting a value for the merchantCapabilities property. You must support 3DS; support of EMV is optional.

通过使用一个字符串常量数组填充supportedNetworks属性标示那个支付网络你支持。通过设置一个值为merchantCapabilities 属性标示那个支付处理协议你支持。你必须支持3DS;支持EMV 是可选的。

The merchant capabilities are bit masks and are combined as follows:

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

标示什么运输和账单信息需要

Populate the requiredBillingAddressFields and requiredShippingAddressFields properties of the payment authorization view controller to indicate what billing and shipping information is needed. When you present this view controller, it prompts the users to supply the requested billing and shipping information. The field constants are combined as follows to set values for these properties:

填充 支付授权 view controller 的 requiredBillingAddressFields 和 requiredShippingAddressFields 属性去标示什么账单和运输信息是需要的。当你展示这个view controller, 它促进用户去支持被请求的账单和运输信息。这个区域场景被如下组合去设置值为哪些属性。

request.requiredBillingAddressFields = PKAddressFieldEmail;

request.requiredBillingAddressFields = PKAddressFieldEmail | PKAddressFieldPostalAddress;

NOTE

Request only the billing and shipping information needed to process your payment and deliver your products or services. Requesting unnecessary information adds unneeded complexity to the transaction. Each additional step increases the chance that the user will simply cancel the payment.

请求仅仅需要账单和运输信息去处理你的支付和发送你的产品或服务。请求不必要的信息添加不需要的复杂到事务。每个附件步骤添加用户将简单取消支付的机会。

If you have up-to-date billing and shipping contact information, you can set those on the payment request. Apple Pay uses this information by default; however, the user can still choose other contact information as part of the payment authorization process.

如果你有更新到日期 账单 和 运输 联系信息,你能在支付请求设置哪些。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;

NOTE

注意

Address information can come from a wide range of sources in iOS. Always validate the information before you use it.

地址信息能从在iOS中资源中很广的范围来。在你用它之前可用让他可用。

Storing Additional Information

存储添加信息

To store information about the payment request that is specific to your app, such as in a shopping cart identifier, use the applicationData property. This property is treated as an opaque value by the system. A hash of the application data appears in the payment token after the user authorizes the payment request.

去存储名确到你app的关于支付请求的信息,比如在一个运输卡identifier,使用applicationData 属性。这个属性被系统作为一个不透明值。一个应用数据的哈西值出现在支付tocken在用户授权了支付请求以后。

Authorizing Payments

授权支付

The payment authorization process is a cooperative effort between the payment authorization view controller and its delegate. A payment authorization view controller does two things: It lets the user select the billing and shipping information that is needed by a payment request, and it lets the user authorize the payment to be made. The delegate methods are called when the user interacts with the view controller so that your app can update the information shown—for example, to update the shipping price when a shipping address is selected. The delegate is also called after the user authorizes the payment request.

支付授权进程是支付授权view controller 和它的代理的 一个合作结果。一个支付授权view controller做两件事:它让用户选择一个支付请求需要的账单和运输信息,和它让用户授权支付被创建。这个代理方法被调用当用户和view controller交换的时候以至于你的app能更新信息展示-比如,去更新运输价格当一个运输地址被选择。这个代理也被调用在用户授权了支付请求以后。

NOTE

注意

As you implement the delegate methods, remember that they can be called multiple times and that the order in which they are called depends on the order of the user’s actions.

随着你实现代理方法,记住他们能被调用多次和他们被调用的顺序取决去用户的动作的顺序。

All of the delegate methods called during the authorization process are passed a completion block as one of their arguments. The payment authorization view controller waits for its delegate to finish responding to one method (by calling the completion block) before it calls any other delegate methods. The paymentAuthorizationViewControllerDidFinish: method is the only exception: It doesn’t take a completion block, and it can be called at any time.

所有在授权处理中被调用的代理方法 被传送一个完成闭包作为一个他们的参数。这个支付授权view controller 等待它的代理去完成响应的方法(通过调用这个完成闭包)在它调用其它代理方法之前。 这个 paymentAuthorizationViewControllerDidFinish: 方法是一个仅有的特例:它不采取一个完成闭包,它可能在任何时候被调用。

The completion blocks take an argument that lets you specify the current status of the transaction based on the information that’s available. If there are no problems with the transaction, you pass the value PKPaymentAuthorizationStatusSuccess; otherwise, you pass a value that identifies the problem.

这个完成闭包用一个让你去明确其中的基于可用信息的交易的状态参数。如果这个交易没有问题,你传送这个值PKPaymentAuthorizationStatusSuccess:否则传送一个值去ID这个问题。

To create an instance of the PKPaymentAuthorizationViewController class, pass the payment request to the view controller’s initializer. Set a delegate for the view controller, and then present it.

去创建一个PKPaymentAuthorizationViewController类的实例,传送支付请求到view controller的实例。设置一个代理为这个view controller,然后展示它。

NOTE

注意

The PKPaymentAuthorizationController class performs the same role as the PKPaymentAuthorizationViewController class, but it does not depend on the UIKit framework. This means that the authorization controller can be used in places where a view controller cannot (for example, in watchOS apps or in Intents extensions).

这个 PKPaymentAuthorizationController 类和PKPaymentAuthorizationViewController类执行相同角色,但是它不依赖UIKit 框架。这就意味这这个授权控制器能被用在view controller不能用的地方(比如,在watchOS中)。

To use the PKPaymentAuthorizationController class, assign an object that adopts the PKPaymentAuthorizationControllerDelegate protocol as a delegate, and call the presentWithCompletion: method to present a payment sheet. When you are done, call thedismissWithCompletion: method to dismiss the payment sheet. Otherwise, the APIs are identical.

去使用这个PKPaymentAuthorizationController 类,赋值一个遵守了PKPaymentAuthorizationControllerDelegate协议的对象作为代理,和调用这个presentWithCompletion:方法去展示一个支付表单。当你完成,调用thedismissWithCompletion:方法去消失这个支付表单。否则接口是相同的。

PKPaymentAuthorizationViewController *viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];

if (!viewController) { /* ... Handle error ... */ }

viewController.delegate = self;

[self presentViewController:viewController animated:YES completion:nil];

As the user interacts with the view controller, the view controller calls its delegate methods.

随着用户和view controller 交互,这个view controller 调用它的代理方法。

NOTE

注意

******In Xcode 7.0 or later, you can test the payment authorization view controller in the simulator. It provides simulated cards for all the supported payment networks and returns dummy payment data in plain text. On a device, this data is encrypted with your merchant identifier and must be decrypted either on your server or by your payment processor.

******在Xcode 7.0或以后,你能测试支付授权view controller在模拟器中******。如果提供了模拟卡为所有支持支付网络和返回虚拟支付数据在文本中。在一个设备中,这个数据被使用你的商户ID加密和必须被你的服务器或你的支付处理者解密。

Use the Apple Pay Sandbox environment to test your app on a device with test cards.

使用Apple Pay Sandbox 环境用一个测试卡去测试你的app在一个设备上。

Although these techniques provide fast and convenient ways to test your code, you still need to thoroughly test Apple Pay on actual, physical devices with production cards.

经管哪些技术提供快速方便方法去测试你的代码,你依旧需要去彻底测试Apple Pay 在真实设备上使用产品卡。

Your Delegate Updates Shipping Methods and Costs

你的代理更新运输方法和花费

When the user provides shipping information, the authorization view controller calls your delegate’s paymentAuthorizationViewController:didSelectShippingContact:completion: and paymentAuthorizationViewController:didSelectShippingMethod:completion: methods. Use these methods to update the payment request based on the new information.

当用户提供运输信息,这个授权view controller 调用你的代理方法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);

}

NOTE

注意

To maintain privacy, the shipping information provided in paymentAuthorizationViewController:didSelectShippingContact:completion: is anonymized. The returned contact contains enough information to calculate shipping costs, without revealing sensitive information about the user. You do not get the user’s full shipping information until after the user approves the payment. Additionally, the data available in the contact changes from country to country, and can change from release to release. Be sure to test your app appropriately.

****去保持私有,这个paymentAuthorizationViewController:didSelectShippingContact:completion:提供运输信息是匿名的。返回的联系包含足够信息去计算运输花费,不用泄漏用户的敏感信息*****。你不能获取用户的完全运输信息直到用户提供支付以后。另外的,在联系中的可用数据从国家到国家改变,从释放到释放改变。确定你合适的测试你的app。

A Payment Token Is Created When a Payment Is Authorized

一个支付Token 被创建当一个支付被授权的时候

When the user authorizes a payment request, the framework creates a payment token by coordinating with Apple’s server and the Secure Element. You send this payment token to your server in the paymentAuthorizationViewController:didAuthorizePayment:completion: delegate method, along with any other information you need to process the purchase—for example, the shipping address and a shopping cart identifier. The process happens as follows:

***当用户授权一个支付请求,这个框架创建一个支付token通过协调 苹果的服务器 和 安全 元素***。你发送这个支付token 到你的服务器在paymentAuthorizationViewController:didAuthorizePayment:completion:代理方法,和其它你需要去处理购买的其它信息-比如,运输地址和一个运输卡ID ,这个过程发生如下:

The framework sends the payment request to the Secure Element. Only the Secure Element has access to the tokenized device-specific payment card numbers.

****这个框架发送支付请求到 安全元素。只有 安全元素能访问到标记化的 设备明确 支付卡号*****。

The Secure Element puts together payment data for the specified card and merchant, encrypts it so that only Apple can read it, and sends it to the framework. The framework then sends the payment data to Apple’s server.

这个安全元素把为直到卡和商户的支付信息防到一起,加密只有苹果能读的方法,发送它到框架。这个框架然后发送支付数据到苹果服务器。

Apple’s server reencrypts the payment data using your Merchant Identifier certificate. The token can only be read by you and the people with whom you have shared your Merchant Identifier certificate. The server then signs the payment token, and returns it to the device.

苹果服务器使用商户ID证书再次加密支付数据。这个token只能被你和你分享了商户ID证书的人读取。这个服务器然后签名这个支付token,然后返回它到设备。

The framework passes the token to your delegate by calling its paymentAuthorizationViewController:didAuthorizePayment:completion: method. Your delegate sends the token to your server.

这个框架通过 调用paymentAuthorizationViewController:didAuthorizePayment:completion方法 传送token 到你的代理。你的代理发送这个token 到你的服务器。

The actions on your server vary depending on whether you process your own payments or work with a payment platform. In both cases, your server handles the order and sends a status back to the device, which your delegate passes to its completion handler, as described in Processing a Payment.

你的服务器的动作取决于是否你处理你的自己的支付或 工作使用一个支付平台。在两个情况下你的服务器处理顺序和发送 状态 到设备,你的代理传送状态到它的完成闭包,就像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

你的代理消失Payment Authorization View Controller

After the framework displays the transaction’s status, the authorization view controller calls your delegate’s paymentAuthorizationViewControllerDidFinish: method. In your implementation, dismiss the authorization view controller and then display your own app-specific order-confirmation page.

在框架展示交易的状态以后,这个授权view controller 调用你的代理的paymentAuthorizationViewControllerDidFinish: 方法。在你的实现中消失授权view controller和展示你自己的app-明确 顺序-配置页面。

- (void) paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller

{

[controller dismissViewControllerAnimated:YES completion:nil];

}

Processing Payments

处理支付

Processing a payment involves several steps:

处理一个支付包含几个步骤:

Sending the payment information to your server, along with other information needed to process the order

发送支付信息到你的服务器,和其它需要去处理订单的信息。

Verifying the hashes and signature of the payment data

验证哈西值和支付数据的签名

Decrypting the encrypted payment data

解密加密的支付信息

Submitting payment data to the payment processing network

提交支付数据到支付处理网络

Submitting the order to your order-tracking system

提交订单到你的订单-追踪 系统

You have two options for processing the payment: You can take advantage of a payment platform to process the payment, or you can implement the payment processing yourself. A payment processing platform typically handles most of the steps listed above.

你有两个选择处理支付:你能利用支付平台去处理支付,或你能自己实现支付处理。一个支付处理平台典型的处理上述步骤中的多数。

Reading, verifying, and processing payment information requires an understanding of several areas of cryptography such as calculating an SHA–1 hash, reading and validating a PKCS #7 signature, and performing elliptic curve Diffie-Hellman key exchange. If you don’t have a background in cryptography, consider using a payment platform that performs these operations for you. For information about payment platforms that support Apple Pay, seedeveloper.apple.com/apple-pay/.

读取,验证和处理支付信息需要理解加密的几个区域比如计算SHA-1哈西,读取和可用一个PKCS #7签名,和执行椭圆曲线Diffe-Hellman 钥匙转化。如果你没有一个加密北京,考虑使用一个支付平台执行哪些操作为你。关于支持Apple Pay 的支付平台信息,参见developer.apple.com/apple-pay/.

The information used to process a payment has a nested data structure, as shown in Figure 5-1. A payment token is an instance of the PKPaymentToken class. The value of its paymentData property is a JSON dictionary, which has a header with information used for validation, and encrypted payment data. The encrypted data includes information such as the amount and cardholder name and other information used for the specific payment processing protocol.

用来去处理一个支付的信息有一个巢数据结构,就像在表5-1中。一个支付token 是 一个PKPaymentToken 类的实例。它的paymentData属性值是一个JSON字典,它有一个有可用信息的头,和被加密的支付数据。这个加密数据保护信息比如钱数和持卡人的名字和其它用来明确支付处理协议的信息。