1.About Apple Pay
Apple Pay是一種移動支付技術,讓使用者把它們對真實的物品和服務的支付信息以一種方便和安全的方式給你。web
對於在app中給出的數字物品和服務,可查看In-App Purchase Programming Guide。json
Working with Apple Pay
使用Apple Pay功能的Apps須要在Xcode 中開啓Apple Pay capabilities。也須要註冊一個商家標識並設置密鑰(用來加密發送支付數據給服務器)。數組
初始化支付時,app建立一個支付請求。該請求包含幾乎所有的服務和商品購買,也包含任何額外的費用:稅金、運費或者折扣。傳送該請求給支付受權視圖控制器,控制器展現該請求給用戶並對任何須要的信息做出提示,例如運送地址或者帳單地址。當用戶與視圖控制器進行交互時,調用代理用以更新請求。安全
一旦用戶受權支付,Apple Pay加密支付信息用以保護未受權的第三方訪問它。在設備上,Apple Pay發送支付請求給加密元件,該元件是一個用戶設備上的專用芯片。該加密元件添加支付信息爲指定的卡和商家生成一個加密的支付密鑰。而後傳遞該密鑰給Apple 服務器,在服務器上使用商家標識證書(Merchant Identifier certificate)解密。最後,服務器傳遞該密鑰返回到app中繼續處理。服務器
支付密鑰從不訪問或者存取在Apple服務器上。該服務器僅僅可以使用證書解密密鑰。這種處理使得不用加密證書app安全的加密支付信息,且必須分配商家標識證書做爲app的一部分。微信
更多關於Apple Pay安全的信息,可查看iOS Security Guide。網絡
大多數狀況下,app傳送加密密鑰給第三發支付平臺解密並處理支付。然而,若是本身的團隊有已經存在的支付基礎設施,能夠在本身的服務器上解密並處理支付。數據結構
更多關於支持Apple Pay的支付平臺的信息,可查看develop.apple.com/apple-pay/。併發
2.Configuring Your Environment
商戶ID用來判別用戶是否對Apple Pay可以接受支付。與商戶ID有關的公共的鑰匙和證書被用來做爲支付進程的一部分,用來加密支付信息。在app可使用Apple Pay以前,須要註冊一個merchant ID商戶ID 並配置它的證書。app
註冊商戶ID(a merchant ID)
1)在會員中心(Member Center),選擇Certificates,Identifiers & Profiles(http://developer.apple.com/account)選項。
2)在Identifiers選項下面,選擇Merchant IDs選項。
3)點擊右上角的添加按鈕(+)。
4)輸入一段描述和標識,點擊Continue繼續按鈕。
5)檢查設置內容,而後點擊Register註冊按鈕。
6)點擊Done 按鈕,完成。
配置商戶ID相應的證書
1)在會員中心(Member Center)(https://developer.apple.com),選擇Certificates,Identifiers & Profiles選項。
2)在Identifiers選項下面,選擇Merchant IDs選項。
3)從列表中選擇商戶ID(merchant ID),點擊Edit編輯按鈕。
4)點擊Create Certificate按鈕生成證書,跟隨得到的說明或是生成一個CSR(certificate signing request),點擊Continue按鈕。
5)點擊選擇文件,選中CSR文件,點擊Generate按鈕。
6)點擊Download按鈕下載該證書,並點擊Done按鈕,完成。
若是在鑰匙串使用中看見一個警告warning ,說明證書被未知的認證受權簽名或者它是一個無效的發行者,確認有the WWDR intermediate certificate - G2證書並在鑰匙串中安裝了the Apple Root CA - G2。這些能夠在apple.com/certificateauthority 下載獲得。
注意:
當出現故障時,有時候這對手動開啓Apple Pay功能有所幫助。跟隨下面的步驟手動開啓Apple Pay功能。
1)在會員中心(Member Center),選擇Certificates ,Identifiers & Profiles選項。
2)在Identifiers選項下,選擇App IDs選項。
3)從列表中選中app ID,點擊Edit按鈕。
4)選擇Apple Pay選項,點擊Edit按鈕。
5)選擇準備使用的商戶IDs(merchant IDs),點擊Continue按鈕。
6)檢查設置內容,而後點擊Assign指派按鈕。
7)點擊Done按鈕,完成。
3.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 = @"Chars"; name.familyName = @"Davy"; 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屬性。該屬性被對待做爲一個系統提供的不透明的值。當用戶受權支付請求以後一大把應用數據會顯示在支付密鑰中。
4.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]; }
5.Processing Payments
處理支付包括這幾步:
1)發送支付信息給服務器,與須要的其它信息一塊兒處理訂單
2)驗證支付數據的哈希表和簽名
3)解密加密的支付數據
4)提交支付數據給支付處理網絡
5)提交訂單給訂單追蹤系統
兩種選擇處理支付:有一個支付平臺的優點去處理支付,或者本身實施支付進程。一個支付處理平臺通常處理大部分如上步驟。
讀取、驗證和處理支付信息須要對密碼學的幾種領域有所理解,例如,計算一個SHA-1 哈希,讀取和驗證一個PKCS #7類型的簽名,和執行elliptic curve Diffie-Hellman key橢圓曲線密鑰交換。若是沒有密碼學的背景,考慮使用一個支付平臺來處理這些操做。更多支持Apple Pay的支付平臺的信息,可查看developer.apple.com/apple-pay/。
用來處理支付的信息有一個嵌套的數據組織,正如展現在Figure 5-1中支付密鑰是PKPaymentToken類的實例。它的paymentData屬性的值是一個JSON字典,它有 個頭部header包含用於確認和加密支付數據的信息。加密數據包含像數量、持卡人姓名和其它用於特定的支付處理協議的的信息。
Figure 5-1Payment data structure
關於支付數據結構格式的詳情,可查看Payment Token Format Reference。
【掃描關注更多精彩內容】
微信公衆號:xiaoniu