iOS開發------Apple Pay(PassKit.framework篇)

由于項目突趕進度,從上次發布iOS開發------Apple Pay(證書配置篇)過去有挺長一段時間了。

俗話說凡事應有始有終,所以還是決定趁空余時間將這篇Apple Pay(PassKit.framework篇)補充完整,萬一有相同疑問的小伙伴呢,好有個參考,也不枉花費的時間。說實話,網上其實有很多介紹Apple Pay的文章,但總是感覺不太詳細,在探索的過程中沒有給我太大的幫助,便把更多的時間執著于開發文檔,由于樓主的英文能力不是很強,也算是花了不少的時間。如果該文有什么錯誤或者誤解,請指正,3Q。

工程的所有代碼已上傳至GitHub(僅供大家研究):https://github.com/RITL/RITLApplePayTest


</img>

啟用Apple Pay

在配置完所有的證書之后,首先記得要在Xcode的項目中啟用Apple Pay模塊。具體位置在TARGET->Capablitiles->Apple Pay,如果配置好了Merchant IDs,那就等一小會就會自動刷新,只需要打上勾即可,如圖。


</img>


支付驗證控制器 -PKPaymentAuthorizationViewController

顧名思義,它就是一個支付驗證的控制器,上圖中模態彈出的控制器其實就是PKPaymentAuthorizationViewController.

類方法-Function

下面是開發文檔中的方法,并通過我的個人理解做的介紹:

//驗證是否能夠進行NFC支付操作--建議模態彈出控制器的時候驗證一下
+ (BOOL)canMakePayments;


//驗證是否能夠支持特定的支付途徑,它的定義存在"PKConstants.h"文件中,下面會介紹一下
+ (BOOL)canMakePaymentsUsingNetworks:(NSArray<NSString *> *)supportedNetworks;


//iOS9_0之后才有的方法,不過個人覺得不太需要擔心,畢竟銀聯支持Apple Pay是iOS9_2之后的
//出了能夠驗證特定的支付途徑之外,還可以驗證支付卡的類型
+ (BOOL)canMakePaymentsUsingNetworks:(NSArray<NSString *> *)supportedNetworks
                        capabilities:(PKMerchantCapability)capabilties NS_AVAILABLE_IOS(9_0);


//代理屬性,對應的協議<PKPaymentAuthorizationViewControllerDelegate>后面也會有記錄
@property (nonatomic, assign, nullable) id<PKPaymentAuthorizationViewControllerDelegate> delegate;


//唯一正確的初始化方法(后面的宏告訴我這是指定的初始化方法)
//記得是參數是nonull(非nil)修飾的呢,如果此參數不正確,那么初始化方法返回的就是nil
- (instancetype)initWithPaymentRequest:(PKPaymentRequest *)request NS_DESIGNATED_INITIALIZER;


支持的支付途徑-SupportedNetworks

下面是定義在PKConstants.h里面的支持的支付途徑

//美國運通(表示沒聽說過0.0 可能和中國的銀聯差不多吧)
extern NSString * const PKPaymentNetworkAmex NS_AVAILABLE(NA, 8_0);

//中國銀聯(這個熟,可以看出要在中國使用銀聯支持的Apple Pay至少要9.2系統)
extern NSString * const PKPaymentNetworkChinaUnionPay NS_AVAILABLE(NA, 9_2);

//萬事達信用卡
extern NSString * const PKPaymentNetworkMasterCard NS_AVAILABLE(NA, 8_0);

//商城的信用卡和借記卡
extern NSString * const PKPaymentNetworkPrivateLabel NS_AVAILABLE(NA, 9_0);

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

//下面兩個不太懂,看不明白..如果有知道的小伙伴們請告知一下
extern NSString * const PKPaymentNetworkDiscover NS_AVAILABLE(NA, 9_0);
extern NSString * const PKPaymentNetworkInterac NS_AVAILABLE(NA, 9_2);


支持支付卡類型-Capabilties

定義在PKPaymentRequest.h的PKMerchantCapability(支付卡)類型

typedef NS_OPTIONS(NSUInteger, PKMerchantCapability) {
    PKMerchantCapability3DS,        //美國的一種卡類型,必須支持!
    PKMerchantCapabilityEMV,        //歐洲的卡
    PKMerchantCapabilityCredit,     //信用卡
    PKMerchantCapabilityDebit       //借記卡
} NS_ENUM_AVAILABLE(NA, 8_0);


支付請求-PKPaymentRequest

作為唯一指定PKPaymentAuthorizationViewController的初始化參數,它的設置直接關系到控制器的生成。
過程中,如果發現初始化的控制器為nil,那么就需要回來看看這個參數是否設置正確,百分之90以上的概率就是它的初始化問題導致了控制器的初始化失敗。

下面是開發文檔中的PKPaymentRequest對象的屬性

必須設置的屬性

//必填,在開發者申請的證書merchantIdentifier的名字
@property (nonatomic, copy) NSString *merchantIdentifier;

//必填,要求兩字母的 ISO 3166 國家代碼,比如中國為"CN"
@property (nonatomic, copy) NSString *countryCode;

//必填,一個存放SupportedNetworks的數據,具體值上面以列出
@property (nonatomic, copy) NSArray<NSString *> *supportedNetworks;

//必填,支持的Capabilties(支付卡類型),具體值上面以列出,可以通過|來支持多種類型
@property (nonatomic, assign) PKMerchantCapability merchantCapabilities;

//必填,存放PKPaymentSummaryItem(支付信息)的數組,并且最后一個必須為總價格,后面會有介紹
@property (nonatomic, copy) NSArray<PKPaymentSummaryItem *> *paymentSummaryItems;

//必填,三字母的 ISO 4217 貨幣代碼,比如人民幣為"CNY"
@property (nonatomic, copy) NSString *currencyCode;

可選設置的屬性

//表示必須需要填寫的訂單地址,默認為PKAddressFieldNone(也就是什么也不寫),具體分類下面有介紹
@property (nonatomic, assign) PKAddressField requiredBillingAddressFields;

//必須的收貨人聯系方式,默認為PKAddressFieldNone
@property (nonatomic, assign) PKAddressField requiredShippingAddressFields;


typedef NS_OPTIONS(NSUInteger, PKAddressField) {
    PKAddressFieldNone              //默認是不需要任何地址
    PKAddressFieldPostalAddress     // 一個完整的地址,包含國家,郵政編碼,省/區,城市,街道,姓名等
    PKAddressFieldPhone             //電話
    PKAddressFieldEmail             //郵箱
    PKAddressFieldName NS_ENUM_AVAILABLE_IOS(8_3)//姓名
    PKAddressFieldAll               //包含以上所有信息
} NS_ENUM_AVAILABLE(NA, 8_0);
//賬單的地址,可能為nil,至于ABRecordRef為什么被廢棄,是ABAddressBook在iOS9.0已經不被推薦使用了
@property (nonatomic, assign, nullable) ABRecordRef billingAddress NS_DEPRECATED_IOS(8_0, 9_0, "Use billingContact instead");
@property (nonatomic, retain, nullable) PKContact *billingContact NS_AVAILABLE_IOS(9_0);


//送貨聯系地址,可能為nil
@property (nonatomic, assign, nullable) ABRecordRef shippingAddress NS_DEPRECATED_IOS(8_0, 9_0, "Use shippingContact instead");
@property (nonatomic, retain, nullable) PKContact *shippingContact NS_AVAILABLE_IOS(9_0);


//存放送貨方式的數組,比如順豐,RILT..等
@property (nonatomic, copy, nullable) NSArray<PKShippingMethod *> *shippingMethods;


//用以保存所需信息的屬性,可能為訂單或這書的唯一標識符,它將被保存在PKPaymentToken中
@property (nonatomic, copy, nullable) NSData *applicationData;
//送貨類型
@property (nonatomic, assign) PKShippingType shippingType NS_AVAILABLE_IOS(8_3);

#pragma - 送貨方法 定義在"PKPaymentRequest.h"
typedef NS_ENUM(NSUInteger, PKShippingType) {
    PKShippingTypeShipping,     //默認為第三方發貨,比如順豐、圓通等..
    PKShippingTypeDelivery,     //賣家自己配送
    PKShippingTypeStorePickup,  //場家直送
    PKShippingTypeServicePickup //買家自提
} NS_ENUM_AVAILABLE(NA, 8_3);


實例:PKPaymentRequest對象

- (PKPaymentRequest *)paymentRequest
{
    PKPaymentRequest * payRequest = [PKPaymentRequest new];
    
    //相關配置
    _payNetworks = @[PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay,PKPaymentNetworkMasterCard];//支持的支付網絡
    //證書identifier
    payRequest.merchantIdentifier = @"merchant.com.yue.ApplePay";
    //兩字母的 ISO 3166 國家代碼
    payRequest.countryCode = @"CN";
    //三字母的 ISO 4217 貨幣代碼
    payRequest.currencyCode = @"CNY";
    //支持的支付網絡
    payRequest.supportedNetworks = _payNetworks;
    //支持的銀行卡類型
    payRequest.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityDebit | PKMerchantCapabilityCredit | PKMerchantCapabilityEMV;
    //支付信息
    payRequest.paymentSummaryItems = self.paymentSummaryItems;
    //必須要有的賬單地址選項,默認為None
    payRequest.requiredBillingAddressFields = PKAddressFieldPostalAddress;
    //必須要有的收貨人聯系方式選項,默認為None
    payRequest.requiredShippingAddressFields = PKAddressFieldPhone | PKAddressFieldPostalAddress;
    //送貨方式,默認為nil
    payRequest.shippingMethods = [self shippingMethods];
    //送貨類型
    payRequest.shippingType = PKShippingTypeDelivery;
    payRequest.applicationData = [@"我是RITL,來收費啦" dataUsingEncoding:NSUTF8StringEncoding];
    
    return payRequest;
}


支付的文本對象-PKPaymentSummaryItem

也就是在上圖中單價,數量等展示的選項,下面是開發文檔中的方法以及屬性:

/*便利構造器*/
+ (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount;
+ (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount type:(PKPaymentSummaryItemType)type NS_AVAILABLE(NA, 9_0);

/*標簽..比如單價、數量等..*/
@property (nonatomic, copy) NSString *label;

/*當前標簽的數組,與NSNumber類型相似,存儲浮點型的對象(與Java中的大整數和大浮點型數字是一樣的)*/
@property (nonatomic, copy) NSDecimalNumber *amount;

/*表示當前ammount的類型*/
@property (nonatomic, assign) PKPaymentSummaryItemType type NS_AVAILABLE(NA, 9_0);

typedef NS_ENUM(NSUInteger, PKPaymentSummaryItemType) {
    PKPaymentSummaryItemTypeFinal,    //表示一個最終的數目,可以理解為一個確認的數目,通常買東西都是固定的吧
    PKPaymentSummaryItemTypePending   //表示一個預計的數目,可變的,比如我們打出租的時候,價格不是固定的起步價吧?
} NS_ENUM_AVAILABLE(NA, 9_0);


實例:PKPaymentSummaryItem

- (NSArray<PKPaymentSummaryItem *> *)paymentSummaryItems
{
    if (_paymentSummaryItems == nil)
    {
        //設置付款選項
        PKPaymentSummaryItem * priceItem = [PKPaymentSummaryItem summaryItemWithLabel:@"單價" amount:[NSDecimalNumber decimalNumberWithString:self.priceTextField.text]];
        
        PKPaymentSummaryItem * numberItem = [PKPaymentSummaryItem summaryItemWithLabel:@"數量" amount:[NSDecimalNumber decimalNumberWithString:self.numberTextField.text]];
        
        //計算總價字符串,最后一個必須是總價
        NSString * sumPrice = [NSString stringWithFormat:@"%@",@(self.priceTextField.text.integerValue * self.numberTextField.text.integerValue)];
        
        PKPaymentSummaryItem * sumItem = [PKPaymentSummaryItem summaryItemWithLabel:@"RITL" amount:[NSDecimalNumber decimalNumberWithString:sumPrice]];
        
        _paymentSummaryItems = @[priceItem,numberItem,sumItem];
    }
    return _paymentSummaryItems;
}


配送方法-PKShippingMethod

PKShippingMethod類繼承自PKPaymentSummaryItem類,但是多了兩個屬性:

//這個必須要寫,作為當前方法的id
@property (nonatomic, copy, nullable) NSString *identifier;

//這個用來類似備注功能的屬性,可以不寫
@property (nonatomic, copy, nullable) NSString *detail;


實例:PKShippingMethod

/// 送貨方式,默認為第一個
- (NSArray<PKShippingMethod *> *)shippingMethods
{
    if (_shippingMethods == nil)
    {
        //設置收貨人送貨選項
        PKShippingMethod * method1 = [PKShippingMethod shippingMethodWithLabel:@"順豐" amountString:@"20" identifier:@"shunfeng" detail:@"預計兩天后到達"];
        
        PKShippingMethod * method2 = [PKShippingMethod shippingMethodWithLabel:@"圓通" amountString:@"18" identifier:@"yuantong" detail:@"預計一天后發貨"];
        
        PKShippingMethod * method3 = [PKShippingMethod shippingMethodWithLabel:@"RITL" amountString:@"5" identifier:@"RITL" detail:@"估計就沒了.."];
        
        _shippingMethods = @[method1,method2,method3];
        
        //默認
        _payModel.shipMethod = method1;
    }

    return _shippingMethods;
}


驗證控制器協議-PKPaymentAuthorizationViewControllerDelegate


必須實現的協議方法

/* 
*   進行驗證并進行回調,并通過回調completion告知控制器是否成功,或失敗原因
*   與銀聯的交互應該在此 
*/
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                       didAuthorizePayment:(PKPayment *)payment
                                completion:(void (^)(PKPaymentAuthorizationStatus status))completion;
/* 驗證完畢或者直接點擊取消進行的回調 */
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller;


可選實現的協議方法

//在Touchid 或者 password(有的銀行還是需要密碼驗證的呢) 驗證之后的回調,點擊取消則不會響應該方法
- (void)paymentAuthorizationViewControllerWillAuthorizePayment:(PKPaymentAuthorizationViewController *)controller NS_AVAILABLE_IOS(8_3)
{

}


//選中一個送貨方式后進行的回調
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                   didSelectShippingMethod:(PKShippingMethod *)shippingMethod
                                completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray<PKPaymentSummaryItem *> *summaryItems))completion
{
    //用來記錄送貨方式
    _payModel.shipMethod = shippingMethod;
    
    //進行回調更新數據
    completion(PKPaymentAuthorizationStatusSuccess,@[shippingMethod]);
}


//選中一個送貨聯系人
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                  didSelectShippingContact:(PKContact *)contact
                                completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray<PKShippingMethod *> *shippingMethods,
                                                     NSArray<PKPaymentSummaryItem *> *summaryItems))completion
{
    //記錄配送聯系人
    _payModel.contact = contact;

    //進行回調更新數據
    completion(PKPaymentAuthorizationStatusSuccess,self.shippingMethods,self.paymentSummaryItems);
    
}


// 選中一個新的支付方式
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                    didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod
                                completion:(void (^)(NSArray<PKPaymentSummaryItem *> *summaryItems))completion
{
    //記錄支付方式
    _payModel.paymentMethod = paymentMethod;

    //進行回調更新數據
    completion(self.paymentSummaryItems);
    
}


真正實現銀聯交互

說白了,Apple Pay只是作為了一個支付入口,真正實現支付作用的還是服務端,至于如何真正的完成支付,請根據下面兩個鏈接進行控件的下載以及CSR證書的配置(CSR證書如何使用,歡迎關注iOS開發------Apple Pay(證書配置篇)注冊App Pay RSA證書模塊),在此吐個槽,下面這兩個網址真TM難找...(為了避免好久之后網址不對,記錄一下當前時間2016-08-24)

下載Apple Pay的開發控件,壓縮文件里面有詳細的規范pdf
https://open.unionpay.com/ajweb/help/file/techFile?productId=80

配置CSR的網址在下面,因為樓主沒法申請商戶賬號,所以想使用Apple Pay進行支付的朋友們,注冊賬號完畢后進行注冊吧.
https://merchant.unionpay.com

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 俗話說凡事應有始有終,所以還是決定趁空余時間將這篇Apple Pay(PassKit.framework篇)補充完...
    卟師閱讀 1,235評論 0 4
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,287評論 25 708
  • 轉載自:Apple Pay的使用 Apple Pay的使用 關于Apple Pay 具體繼承步驟也可參考: 網址配...
    John_LS閱讀 1,032評論 5 0
  • 1.About Apple Pay Apple Pay是一種移動支付技術,讓使用者把它們對真實的物品和服務的支付信...
    NEWWORLD閱讀 5,259評論 14 51
  • 人生是一個不斷做選擇的過程,在這個過程里,誰擁有了更多的選擇權,誰就擁有了飽滿的幸福。 現如今,對讀書這件事,有著...
    放飛心晴閱讀 1,888評論 1 2