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