Apple Pay的使用

John_LS發表於2016-02-18

轉載自:http://blog.sina.com.cn/s/blog_6f7ca9e90102w1l3.html

Apple Pay的使用

關於Apple Pay 具體繼承步驟也可參考http://www.cocoachina.com/ios/20141023/10026.html

配置支付環境建立支付請求授權支付支付處理Part 1 關於Apple Pay

Apple Pay是一種移動支付技術,它能夠讓使用者以一種便捷安全的方式為現實世界中購買的商品和服務付款。


在Xcode和蘋果開發者會員中心中配置Apple Pay

使用Apple Pay的APP需要一項特殊的許可權,該許可權可以在開發者會員中心和Xcode中開啟。你同樣需要註冊一個商業標示,並設定金鑰;在給伺服器傳送支付資訊時,這些密匙可以確保資料的安全傳輸。

相關章節:配置支付環境(Configuring Your Environment,後面會提到)

使用者授權支付請求

支付請求就是描述當前進行的購買操作,包括支付金額。你把支付請求傳送給一個授權支付的檢視控制器;該試圖控制器呈現相關請求內容,並提示使用者需要輸入的資訊,例如配送地址或者賬單地址。接著,當使用者與檢視控制器互動,並提供新的支付資訊時,APP會呼叫支付請求的委託,繼續執行支付流程。

相關章節:建立支付請求(Creating a Payment Request),授權支付(Authorizing a Payment)(後面會提到)

伺服器處理支付請求

Apple Pay會對支付資訊進行加密處理,以防止未獲授權的第三方獲取使用者的支付資訊。你可以在自己的伺服器上完成整個支付流程,也可以在自己的伺服器上使用第三方支付平臺來解碼支付資訊,並完成支付處理。

關於支援Apple Pay的支付平臺資訊,請參考developer.apple.com/apple-pay/

相關章節:處理支付請求(Processing a Payment

Part 2 配置支付環境

一個商用ID標識可以幫助Apple Pay識別你,讓你能夠接受付款。在支付資訊加密的過程中,把公匙和證書與ID標示關聯起來進行加密是必不可少的一步。在APP使用Apple Pay之前,你首先得註冊一個商用ID,並配置它的相關證書。

註冊商用ID標示

  1. 在開發者會員中心,選擇“Certificates,Identifiers&Profiles
  2. 在Identifiers下,選擇Merchant IDs
  3. 在右上角點選"+"按鈕
  4. 在Description欄、ID欄輸入相應資訊,點選"Continue"
  5. 瀏覽下配置引數,點選"Register"
  6. 點選"Done"

為你的ID標示配置一個證書

  1. 在開發者會員中心,選擇"Certificates,Identifiers&Profiles"
  2. 在Identifiers下,選擇Merchant IDs
  3. 選擇列表中的ID標示,點選Edit
  4. 點選"Create Certificate",按照指示獲取或生成簽名證書請求(CSR),點選"Continue"
  5. 點選"Choose File",選擇你的CSR,點選"Generate"
  6. 點選"Download"下載證書,點選"Done"

如果KeyChain Access中顯示了警示資訊,表示未知授權簽發證書或者無效證書發行人,那麼要確保你已經在鑰匙鏈中安裝了WWDR中級證書-G2和Apple Root CA-G2。你可以在這個地方下載這些東西:apple.com/certificateauthority.

為了在Xcode中啟用Apple Pay,開啟APP工程檔案的Capabilities皮膚。在Apple Pay這行將開關按鈕設定為"ON",接著選擇APP需要使用的ID標示。


注意:在APP排錯時,偶爾手動啟用Apple Pay很管用。請按照以下步驟手動啟用Apple Pay:

  1. 在會員中心,選擇Certificates,Identifiers& Profiles
  2. 在Identifiers下,選擇App IDs
  3. 選擇列表中的app ID,點選"Edit"
  4. 選擇 Apple Pay ,點選"Edit"
  5. 選擇你需要使用的ID標示,點選"Continue"
  6. 瀏覽配置引數,點選"Assign"
  7. 點選"Done"

Part 3 建立支付請求

建立支付請求

支付請求是PKPaymentRequest類的例項,它的組成部分包括一個用來表示將要購買的專案的摘要,一個可用的配送方式列表,一個表示使用者需要提供的配送資訊的描述,以及一些商家和支付平臺的資訊。

判定使用者是否能夠支付

在建立支付請求之前,要首先通過呼叫PKPaymentAuthorizationViewController 類裡的canMakePaymentsUsingNetworks:方法來判斷使用者是否能夠使用你提供的支付網路進行支付。如果要判斷使用者的硬體是否支援Apple Pay或者是否因為家長控制而不能支付,請使用canMakePayments 方法。

如果使用者不能進行支付,那就不要顯示支付按鈕,相應的應該退回到其它支付方式。

支付請求包含貨幣和地區資訊

所有的彙總金額應該使用同一種貨幣,貨幣的資訊可使用PKPaymentRequest類的currencyCode屬性進行指定。像"USD"這樣,使用3個字元格式的ISO貨幣編碼。

一個支付請求裡的國家程式碼表示了這次購買發生的國家或者將要在這個國家處理這次支付。像"US"這樣,使用2個字元格式的ISO國家編碼。

在支付請求裡指定的商用ID必須匹配應用中指定的商用ID列表之一。

1

2

3

request.currencyCode = @"USD";

request.countryCode = @"US";

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

支付請求包含一個支付摘要專案的列表

支付摘要專案,屬於PKPaymentSummaryItem 類,描述了支付請求的不同部分。在一個支付請求裡不要使用太多的摘要專案---典型的專案像比如小計金額、折扣資訊、配送資訊、含稅資訊以及總計金額等。如果你想要提供更詳細的支付專案列表,可以在你應用的其它地方提供。

每一個摘要專案會有一個標籤和數額,就像在程式碼列表3-1中顯示的那樣。標籤文字是一個使用者可閱讀的摘要專案描述資訊,數額是相對應的支付數額。在一個支付請求中所有的數額都要使用在這個請求中指定的貨幣。對於折扣或優惠券,則需要把數額設成負數。

Listing 3-1建立支付專案

1

2

3

4

5

6

7

// 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為底數的數值。可以使用指定尾數和指數的方式(像程式碼中那樣)來建立這個類的例項,也可以通過指定字串和locale來例項化,字串指定了相應的數值。這裡總是使用以10為底數的數值來做財務計算--例如當需要計算5%折扣掉的金額時。

儘管有時使用其它的計數方法更方便,但是像float或者Double這樣的IEEE浮點數型別是不適合作財務計算的,這些資料型別使用的是以2為底數的數值表示方法,這就表示有一些十進位制數值不能準確得被表示--例如0.42必須以0.41999這樣的迴圈小數來近似表示,而這種近似表示常常會造成財務計算的錯誤結果。

在這個摘要專案列表中的最後一個是總計金額。這個金額是通過把所有其它金額相加而得到。總計的顯示方法和其它的摘要專案不同:應該使用你公司的名稱做為其標籤,使用所有其它專案的金額總和做為金額。使用paymentSummaryItems 屬性將這些摘要專案加入支付請求。

1

2

3

4

5

6

7

// 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;

配送方式是一種特殊的摘要專案

對於每一種可用的配送方式建立一個PKShippingMethod的例項。就像其它支付摘要專案一樣,配送方式包含使用者易於辨別的標籤,比如"標準配送"或者"第二天配送",還有一個金額來表示配送費用。與其它摘要專案不同的是,配送方式還有一個detail屬性--像"7月29日到達"或者"24小時之內配送"等--可以用來解釋各個配送方式之間的區別。

使用identifier屬性來在代理方法中區分不同的配送方式,這個屬性只會在你的應用內使用--框架看不到這個屬性,並且它也不會出現在UI中。在建立配送方式時為其分配一個獨一無二的識別符號。為了方便除錯,可使用文字縮寫,比如"discount", "standard", 或者 "next-day".

有一些配送方式在某些地區可能不適用,或者有不同的價格,你可以在使用者選擇配送地址或配送方式的代理方法時更新這些資訊,就像Your Delegate Updates Shipping Methods and Costs描述的一樣。

指定你支援的支付方式

通過在supportedNetworks屬性中填入字串常量陣列來指定你支援的支付網路。通過指定merchantCapabilities屬性來指定你支援的支付處理標準,3DS支付方式是必須支援的,EMV方式是可選的。

商家支援的支付處理標準使用標識位來進行組合,像下面這樣:

1

2

3

4

5

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

// Supports 3DS only

request.merchantCapabilities = PKMerchantCapability3DS;

// Supports both 3DS and EMV

request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV;

指示所需配送資訊和賬單資訊

通過填充 requiredBillingAddressFields 和 requiredShippingAddressFields屬性來指定所需賬單資訊和配送地址資訊。當你顯示一個檢視控制器時,它會提示使用者輸入所需內容。這些欄位常量可以像下面這樣進行組合來設定這些屬性:

1

2

request.requiredBillingAddressFields = PKAddressFieldEmail;

request.requiredBillingAddressFields = PKAddressFieldEmail | PKAddressFieldPostalAddress;

如果你已經有了使用者的賬單和配送資訊,可以直接在支付請求中使用它們。但是儘管Apple Pay預設使用了這些資訊,使用者仍然可以在授權支付的過程中修改這些資訊。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

ABRecordRef record = ABPersonCreate();

CFErrorRef error;

BOOL success;

success = ABRecordSetValue(record, kABPersonFirstNameProperty, @"John", &error);

if (!success) {  }

success = ABRecordSetValue(record, kABPersonLastNameProperty, @"Appleseed", &error);

if (!success) {  }

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) {  }

request.shippingAddress = record;

CFRelease(shippingAddress);

CFRelease(record);

儲存額外資訊

使用applicationData屬性來儲存一些在你的應用中關於這次支付請求的唯一標識資訊,比如一個購物車的識別符號。在使用者授權支付之後,這個屬性的雜湊值會出現在這次支付的token中。

part 4 授權支付

支付授權過程是由支付授權view controller和它的代理協作完成的。支付授權view controller做了兩件事情:它讓使用者選擇支付請求所必需的賬單和配送資訊,還有讓使用者最終授權同意這次支付。當使用者和view controller互動時,代理方法就會被呼叫,這樣你的應用就可以不斷地更新顯示的資訊--例如在配送地址更改後更新配送費用。使用者最終授權支付請求之後代理方法同樣也會被呼叫。

注意:在實現這些方法時注意,這些方法可能會被多次呼叫,而它們被呼叫的順序取決於使用者的行為的順序。

在所有這個授權過程中被呼叫的代理方法中,都會有一個completion block被做為引數之一傳入,支付授權view controller會在一個代理方法執行完畢(通過呼叫completion塊)後再呼叫另一個代理方法。唯一的例外是paymentAuthorizationViewControllerDidFinish:方法:它不包含completion block,所以它可以在任何時候被呼叫。

這個completion block有一個傳入引數,基於現有的可用資訊,你可以通過這個引數並指定這次交易的狀態。如果這次交易沒有任何問題,傳入PKPaymentAuthorizationStatusSuccess,否則,你要傳入一個識別問題的值。

通過在PKPaymentAuthorizationViewController類的構造方法中傳入一個支付請求來對它進行例項化,然後給這個檢視控制器設定一個代理,就可以把它展示給使用者了。

1

2

3

4

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

if (!viewController) {  }

viewController.delegate = self;

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

當使用者與這個檢視控制器進行互動時,它的代理方法會被呼叫。

通過代理更新配送方式和費用

當使用者提供配送資訊之後,授權view controller 會呼叫paymentAuthorizationViewController:didSelectShippingAddress:completion: paymentAuthorizationViewController:didSelectShippingMethod:completion:這兩個代理方法。在這兩個方法中根據最新資訊來更新支付請求。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller

                   didSelectShippingAddress:(ABRecordRef)address

                                 completion:(void (^)(PKPaymentAuthorizationStatus, NSArray *, NSArray *))completion

{

    self.selectedShippingAddress = address;

    [self updateShippingCost];

    NSArray *shippingMethods = [self shippingMethodsForAddress:address];

    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);

}

當支付被授權後,支付token會被建立

當使用者最終授權了一個支付請求,框架會通過與蘋果伺服器和嵌入在裝置中的一個安全模組進行通訊,生成一個支付token。然後你在paymentAuthorizationViewController:didAuthorizePayment:completion:方法中將這個token和其它一些你需要用來處理這次購買的資訊--例如配送地址和購物車標識--傳送給你的伺服器。這個過程是這樣的:

  • 框架傳送支付請求給安全模組,只有安全模組可以訪問儲存在裝置上的標記化的卡資訊。
  • 安全模組把特定的卡和商家等支付資料加密,以保證只有蘋果可以讀取,然後傳送給框架。框架會將這些資料傳送給蘋果。
  • 蘋果伺服器再次加密這些支付資料,以保證只有商家可以讀取。然後伺服器對它進行簽名,生成支付token,然後傳送給裝置。
  • 框架呼叫相應的代理方法並傳入這個token,然後你的代理方法傳送token給你的伺服器。

至於你的伺服器採取的行為要取決於你是自己處理這次支付或者你是和其它支付平臺合作來進行支付處理。不管怎樣,你的伺服器處理這個訂單然後傳送一個狀態資訊給裝置,代理方法會把這個狀態資訊傳送給completion塊,像在“Processing a Payment”中討論過的。

1

2

3

4

5

6

7

8

9

10

11

12

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

}

在代理方法中釋放授權View Controller

在框架顯示交易狀態之後,授權View Controller會呼叫代理paymentAuthorizationViewControllerDidFinish:的方法。在這個方法的實現中,先釋放授權頁面控制器再顯示你自己的訂單確認頁面。

1

2

3

4

- (void) paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller

{

[controller dismissViewControllerAnimated:YES completion:nil];

}

Part 5 支付處理

處理一個支付請求涉及以下幾個步驟:

  1. 把支付資訊,以及支付流程+所需的其他資訊,一起傳送給你的伺服器。
  2. 驗證支付資料的雜湊表和簽名
  3. 為加密過的支付資料解碼
  4. 向支付處理系統提交支付資料
  5. 向訂單追蹤系統提交訂單

處理支付請求時,你有兩個選擇;你既可以利用支付平臺處理支付請求,也可以自己實現支付請求處理流程。一個常用的支付平臺可以完成上述大部分操作。

讀取,驗證,以及處理支付資訊需要有一定的相關密碼知識,例如計算SHA-1雜湊表,讀取和驗證PKCS#7簽名,執行Elliptic Curve Diffie-Hellman密匙交換。如果沒有一定的密碼學背景,你可以考慮使用第三方支付平臺來完成這些操作。

關於支援Apple Pay支付平臺的更多資訊,請參考developer.apple.com/apple-pay/

處理支付請求所用的資訊擁有一種巢狀式的資料結構,如下圖。支付令牌是PKPaymentToken類的例項。其paymentData屬性值是一個JSON詞典,它的標頭檔案資訊可以用來驗證和加密支付資料。加密過的資料資訊包括支付金額、持卡人姓名,以及一些其他指定的支付處理協議。

相關文章