關(guān)于 Apple Pay
apple pay 是一種移動支付技術(shù),它可以讓用戶將自己在現(xiàn)實生活中購物、享受服務(wù)的支付信息提供給我們,它是一種方便而且安全的支付方式。
使用 Apple Pay 的 APP 需要在 Xcode 中打開 Apple Pay 功能,同時需要注冊一個商戶ID,并設(shè)置好加密密鑰,這個密鑰是用來將支付數(shù)據(jù)安全地發(fā)送到我們自己的服務(wù)器。
在開始一次支付時,APP 需要創(chuàng)建一個支付請求。這個支付請求不僅包含了已購買的服務(wù)或者商品的一些合計,同時也包含了稅金、配送費或者是折扣等一些附加費用的信息。將這個請求傳遞給一個payment authorization view controller ,這個控制器將支付請求的信息顯示出來,并提示用戶一些必要信息,例如配送地址或者賬單寄送地址。在用戶與這個view controller 交互時,會調(diào)用delegate來更新支付請求。
一旦用戶對這次支付授權(quán)完成,Apple Pay 會將支付信息加密,以防止未授權(quán)的第三方來訪問這些信息。在用戶的設(shè)備上,Apple Pay 發(fā)送了一個支付請求到 Secure Element,SE 是在設(shè)備上專門保證安全的一塊芯片。SE 會將用戶指定銀行卡信息和商戶信息添加到支付請求中去,并且創(chuàng)建一個加密的支付 token 。然后將這個 token 發(fā)送到蘋果服務(wù)器,蘋果服務(wù)器會使用我們提供的商戶ID證書將支付請求再次加密。最后服務(wù)器會將這個請求返回到應(yīng)用中來進(jìn)行后續(xù)的操作。蘋果服務(wù)器不會訪問或者保存支付 token,服務(wù)器只是簡單的將 token 用開發(fā)者的證書再次加密。
大部分情況下,應(yīng)用將加密過的支付 token 發(fā)送到第三方支付平臺解密并完成支付。也可以在自己的服務(wù)器上完成界面和支付的過程。
配置支付環(huán)境
首先我們需要一個 Merchant ID,這樣 Apple Pay 才能夠識別出接收支付的對象。公鑰和證書會跟我們的 Merchant ID 關(guān)聯(lián),在加密支付信息操作時會用到它們。使用 Apple Pay 之前要先注冊一個 Merchant ID 并且配置好證書。
http://developer.apple.com/account 在這里注冊 Merchant ID 和配置證書。
然后在工程的 Capabilities 窗口中將 Apple Pay 打開,選中想要該應(yīng)用使用的 Merchant ID。
創(chuàng)建支付請求
支付請求是 PKPaymentRequest 類的一個實例。一個支付請求由以下幾部分組成:一個為用戶描述支付項目的摘要列表、一個可用的配送信息列表、一段提示用戶提供配送信息的文案,以及一些商戶信息和支付平臺的信息。
判斷用戶是否可用 Apple Pay 支付
在創(chuàng)建支付請求之前,要先調(diào)用 PKPaymentAuthorizationViewController 類中的 canMakePaymentUsingNetworks: 方法來判定用戶能不能用我們提供的支付系統(tǒng)來進(jìn)行支付。如果要檢查用戶的設(shè)備硬件是否支持 Apple Pay ,或者檢查是否因“家長控制”功能開啟而導(dǎo)致不能支付的情況,那么要調(diào)用 canMakePayments 方法。
如果canMakePayments返回了NO,說明這個設(shè)備不支持 Apple Pay ,這時候就不應(yīng)該顯示 Apple Pay 按鈕,而是通過其他支付方式來支付。
如果 canMakePayments 返回了 YES 但是 canMakePaymentUsingNetworks: 返回NO時,說明設(shè)備支持 Apple Pay ,但是用戶沒有為任何支付網(wǎng)絡(luò)系統(tǒng)添加銀行卡。此時我們可以視情況來顯示一個支付設(shè)置按鈕來提示用戶設(shè)置新的銀行卡,用戶點擊設(shè)置時需要調(diào)用 openPaymentSetup 方法。
支付請求要包含貨幣以及區(qū)域信息
在一個支付請求中所有項目的金額必須使用同一種貨幣,貨幣種類要在 PKPaymentRequest 的 currencyCode 屬性中指定。使用 ISO 統(tǒng)一的三字符編碼來規(guī)定指定的貨幣種類,例如 USD ,CNY。請求當(dāng)中的國家編碼表明了此次購買的位置處于哪個國家,或者處理購買支付的國家。使用 ISO 兩字符編碼來表示國家,例如US、CN。
請求中指定的Merchant ID 必須是包含在應(yīng)用的 Merchant ID 列表當(dāng)中。
支付請求包含一個支付摘要項目的列表
支付摘要項目是用 PKPaymentSummaryItem 類的對象表示的,每一項都描述了支付請求的不同部分。要盡量控制摘要項目的數(shù)量,比如費用小計、折扣金額、配送信息、稅金、總計金額等。如果沒有這些額外費用的話,就直接顯示總金額。不要把這些摘要子項的內(nèi)容一個一個在支付請求中列出來,應(yīng)該在別的地方顯示給用戶。
每一個摘要項目都含有一個標(biāo)簽和一個金額,所有的金額都是表示支付請求當(dāng)中指定貨幣類型的金額,如果是支付請求中包含折扣或者優(yōu)惠券,那么要用負(fù)數(shù)來表示金額。表示金額的時候要使用 NSDecimalNumber 這個類,因為 NSDecimalNumber 使用的是以10為底數(shù),指定尾數(shù)和指數(shù)的方式來表示數(shù)值,財務(wù)運算中不適合使用浮點型的數(shù)來表示數(shù)額,因為有些十進(jìn)制的數(shù)額不能用浮點型精確的表示出來,例如0.42可能會被以0.419999...的循環(huán)小數(shù)來表示,這就會造成計算錯誤。
通過支付請求的 paymentSummaryItems 屬性來向該請求的摘要項目列表中添加支付摘要項目。支付摘要項目列表是一個數(shù)組,它的最后一項用來表示這個支付請求的總金額,總金額是需要我們自己計算的,通過把各個摘要項目相加而得到總金額。總金額的顯示方式會跟其他摘要項目有一些差別,這里需要使用公司的名稱作為總金額的標(biāo)題。
配送方式是一種特殊的摘要項目
每一種可用的配送方式都需要創(chuàng)建一個 PKShippingMethod 實例。它同其它的摘要項目一樣具有標(biāo)簽和金額,標(biāo)簽是易于用戶識別不同配送方式的文案,例如“次日送達(dá)”或者“標(biāo)準(zhǔn)配送”,金額表示不同配送方式的費用。PKShippingMethod 對象有兩個屬性,identifier 是配送方式的唯一標(biāo)識符,detail 是各個配送方式的描述。
指明應(yīng)用所支持的支付處理機(jī)制
通過字符串常量數(shù)組擴(kuò)充 supportedNetworks 屬性來指明我們的應(yīng)用所支持的支付網(wǎng)絡(luò)系統(tǒng)。通過設(shè)置 merchantCapabilities 屬性的值來指明我們所支持的支付處理協(xié)議。必須支持 3DS (Three Domain Secure)協(xié)議,對于 EMV 的支持是可選的。
額外信息的儲存
使用 applicationData 屬性在應(yīng)用中儲存關(guān)于本次支付的一些標(biāo)識信息,例如購物車的唯一標(biāo)識符。這個值對于系統(tǒng)來說是不可見的,在用戶授權(quán)支付以后,這個屬性會以一個 hash 值的形式出現(xiàn)在支付請求的 token 當(dāng)中。
支付的授權(quán)
授權(quán)支付的處理是由支付授權(quán)控制器和它的 delegate 共同協(xié)作完成的。支付授權(quán)控制器處理兩件事:它讓用戶選擇支付請求中所必須的賬單和配送信息,并讓用戶對這次支付進(jìn)行授權(quán)。當(dāng)用戶與支付授權(quán)控制器交互時,delegate的方法就會被調(diào)用,以便應(yīng)用能夠更新信息的顯示。并且在用戶授權(quán)支付之后 delegate 方法也會被調(diào)用。這些 delegate 方法可能會被多次調(diào)用,調(diào)用的順序取決于用戶的操作順序。
在授權(quán)支付的過程中,所有的 delegate 方法在被調(diào)用時都會傳入一個 completion block 參數(shù),支付授權(quán)控制器會等待它的 delegate 響應(yīng)完前一個 delegate 方法之后才回去調(diào)用另一個 delegate 方法,delegate 通過執(zhí)行參數(shù)中的 block 來完成響應(yīng)。
在 completion block 中攜帶的參數(shù)可以讓我們根據(jù)可用的信息來指定當(dāng)前的支付狀態(tài)。如果當(dāng)前的交易狀態(tài)沒有問題,那么就傳入 PKPaymentAuthorizationStatusSuccess 參數(shù),否則需要傳入一個能識別問題的參數(shù)。
在創(chuàng)建 PKPaymentAuthorizationViewController 實例時,需要在初始化傳入支付請求。隨后為這個 view controller 設(shè)置 delegate 并將這個 view controller 顯示出來。用戶與這個view controller 交互時會回調(diào) delegate 方法。
通過 paymentAuthorizationViewController:didSelectShippingContact:completion: 方法和paymentAuthorizationViewController:didSelectShippingMethod:completion: 方法來回調(diào) delegate 更新配送聯(lián)系信息和配送方式,我們需要在delegate 中更新配送費用。
當(dāng)支付請求被授權(quán)時支付token會被創(chuàng)建
用戶授權(quán)了支付請求后,PK 框架通過跟蘋果服務(wù)器和 Secure Element 的協(xié)作來創(chuàng)建支付 token 。我們需要在 paymentAuthorizationViewController:didAuthorizePayment:completion: 這個 delegate 方法中,把支付 token 連同我們需要的所有與交易相關(guān)的信息發(fā)送到自己的服務(wù)器上,例如購物車唯一標(biāo)識符或者配送地址等等信息。這個過程大致如下:
- PK 框架把支付請求發(fā)送到 Secure Element 。只有 Secure Element才可以訪問到用戶設(shè)備上已經(jīng)被符號化的支付卡卡號。
- Secure Element 把指定的卡信息和商戶等等支付數(shù)據(jù)加密成蘋果能讀取的形式,然后將加密后的數(shù)據(jù)發(fā)送到框架中,框架再把加密過的數(shù)據(jù)發(fā)送到蘋果的服務(wù)器。
- 蘋果的服務(wù)器會使用開發(fā)者提供的商戶ID證書將這些支付數(shù)據(jù)再次加密。再次加密完成后,蘋果服務(wù)器會對支付數(shù)據(jù)簽名并生成 token 發(fā)送到用戶的設(shè)備上,只有擁有商戶ID證書的人才能讀取加密過的 token 。
- PK 框架會把這個 token 通過調(diào)用 paymentAuthorizationViewController:didAuthorizePayment:completion: 方法來回調(diào) delegate ,我們拿到 token 后要發(fā)送到自己的服務(wù)器。
在我們自己的服務(wù)器上的操作是根據(jù)不同情況來決定的,我們可以自己處理支付或者使用其他的支付平臺來處理支付。不論是哪一種情況,我們自己的服務(wù)器都要處理支付的訂單并將支付狀態(tài)返回到設(shè)備上,在 paymentAuthorizationViewController:didAuthorizePayment:completion: 方法中處理支付狀態(tài),并在 completion block 中將狀態(tài)傳遞給支付授權(quán)控制器。
授權(quán)結(jié)束后釋放支付授權(quán)控制器
在 PassKit 框架顯示交易狀態(tài)之后,支付授權(quán)控制器會調(diào)用 delegate 的方法 paymentAuthorizationViewControllerDidFinish: ,在這個 delegate 方法的實現(xiàn)中,delegate 要將支付授權(quán)控制器關(guān)閉,然后再顯示應(yīng)用自己的訂單支付確認(rèn)頁面。
支付處理
處理支付包含下列幾個步驟:
- 把支付信息和訂單所需要的其他信息一起發(fā)送到我們自己的服務(wù)器
- 驗證支付數(shù)據(jù)當(dāng)中的哈希表和簽名
- 將加密的支付數(shù)據(jù)解密出來
- 向支付處理系統(tǒng)提交支付數(shù)據(jù)
- 向我們自己的訂單系統(tǒng)提交訂單
我們有兩種方式來處理支付:我們可以利用支付平臺來處理支付,或者我們自己實現(xiàn)支付處理過程。一個支付處理平臺基本上就能完成上述的大部分操作。
要讀取、驗證和處理支付信息,就必須知道一部分密碼學(xué)知識,比如計算SHA—1哈希表,讀取和驗證 PKCS#7 簽名和Diffie-Hellman 橢圓曲線密鑰交換。如果我們不具有這些密碼學(xué)的知識背景,那么可以考慮使用第三方支付平臺來完成這些操作。
用來處理支付的信息是一種嵌套式的數(shù)據(jù)結(jié)構(gòu),支付 token 是一個 PKPaymentToken 類的實例。它的 paymentData 屬性的值是一個 JSON 字典。這個 JSON 字典的 Header 包含用來驗證支付信息和加密支付數(shù)據(jù)。加密的支付信息包含諸如訂單總額、持卡人姓名和用來指定支付處理協(xié)議的其他信息。
相關(guān)知識文檔:
Apple Pay Programming Guide
WWDC 2015 Apple Pay Within Apps
Getting Started With Apple Pay
PKPaymentAuthorizationViewController Class Reference
iOS Security Guide