由于項目突趕進(jìn)度培慌,從上次發(fā)布iOS開發(fā)------Apple Pay(證書配置篇)過去有挺長一段時間了。
俗話說凡事應(yīng)有始有終篇裁,所以還是決定趁空余時間將這篇Apple Pay(PassKit.framework篇)
補(bǔ)充完整沛慢,萬一有相同疑問的小伙伴呢,好有個參考达布,也不枉花費(fèi)的時間团甲。說實話,網(wǎng)上其實有很多介紹Apple Pay的文章黍聂,但總是感覺不太詳細(xì)躺苦,在探索的過程中沒有給我太大的幫助,便把更多的時間執(zhí)著于開發(fā)文檔产还,由于樓主的英文能力不是很強(qiáng)匹厘,也算是花了不少的時間。如果該文有什么錯誤或者誤解脐区,請指正愈诚,3Q。
工程的所有代碼已上傳至GitHub(僅供大家研究):https://github.com/RITL/RITLApplePayTest
啟用Apple Pay
在配置完所有的證書之后牛隅,首先記得要在Xcode的項目中啟用Apple Pay模塊炕柔。具體位置在TARGET->Capablitiles->Apple Pay,如果配置好了Merchant IDs媒佣,那就等一小會就會自動刷新匕累,只需要打上勾即可,如圖默伍。
</img>
支付驗證控制器 -PKPaymentAuthorizationViewController
顧名思義欢嘿,它就是一個支付驗證的控制器,上圖中模態(tài)彈出的控制器其實就是PKPaymentAuthorizationViewController
.
類方法-Function
下面是開發(fā)文檔中的方法也糊,并通過我的個人理解做的介紹:
//驗證是否能夠進(jìn)行NFC支付操作--建議模態(tài)彈出控制器的時候驗證一下
+ (BOOL)canMakePayments;
//驗證是否能夠支持特定的支付途徑际插,它的定義存在"PKConstants.h"文件中,下面會介紹一下
+ (BOOL)canMakePaymentsUsingNetworks:(NSArray<NSString *> *)supportedNetworks;
//iOS9_0之后才有的方法显设,不過個人覺得不太需要擔(dān)心框弛,畢竟銀聯(lián)支持Apple Pay是iOS9_2之后的
//出了能夠驗證特定的支付途徑之外,還可以驗證支付卡的類型
+ (BOOL)canMakePaymentsUsingNetworks:(NSArray<NSString *> *)supportedNetworks
capabilities:(PKMerchantCapability)capabilties NS_AVAILABLE_IOS(9_0);
//代理屬性捕捂,對應(yīng)的協(xié)議<PKPaymentAuthorizationViewControllerDelegate>后面也會有記錄
@property (nonatomic, assign, nullable) id<PKPaymentAuthorizationViewControllerDelegate> delegate;
//唯一正確的初始化方法(后面的宏告訴我這是指定的初始化方法)
//記得是參數(shù)是nonull(非nil)修飾的呢瑟枫,如果此參數(shù)不正確,那么初始化方法返回的就是nil
- (instancetype)initWithPaymentRequest:(PKPaymentRequest *)request NS_DESIGNATED_INITIALIZER;
支持的支付途徑-SupportedNetworks
下面是定義在PKConstants.h
里面的支持的支付途徑
//美國運(yùn)通(表示沒聽說過0.0 可能和中國的銀聯(lián)差不多吧)
extern NSString * const PKPaymentNetworkAmex NS_AVAILABLE(NA, 8_0);
//中國銀聯(lián)(這個熟指攒,可以看出要在中國使用銀聯(lián)支持的Apple Pay至少要9.2系統(tǒng))
extern NSString * const PKPaymentNetworkChinaUnionPay NS_AVAILABLE(NA, 9_2);
//萬事達(dá)信用卡
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的初始化參數(shù)允悦,它的設(shè)置直接關(guān)系到控制器的生成膝擂。
過程中,如果發(fā)現(xiàn)初始化的控制器為nil,那么就需要回來看看這個參數(shù)是否設(shè)置正確架馋,百分之90以上的概率就是它的初始化問題導(dǎo)致了控制器的初始化失敗狞山。
下面是開發(fā)文檔中的PKPaymentRequest對象的屬性
必須設(shè)置的屬性
//必填,在開發(fā)者申請的證書merchantIdentifier的名字
@property (nonatomic, copy) NSString *merchantIdentifier;
//必填,要求兩字母的 ISO 3166 國家代碼,比如中國為"CN"
@property (nonatomic, copy) NSString *countryCode;
//必填叉寂,一個存放SupportedNetworks的數(shù)據(jù)萍启,具體值上面以列出
@property (nonatomic, copy) NSArray<NSString *> *supportedNetworks;
//必填,支持的Capabilties(支付卡類型)屏鳍,具體值上面以列出勘纯,可以通過|來支持多種類型
@property (nonatomic, assign) PKMerchantCapability merchantCapabilities;
//必填,存放PKPaymentSummaryItem(支付信息)的數(shù)組,并且最后一個必須為總價格钓瞭,后面會有介紹
@property (nonatomic, copy) NSArray<PKPaymentSummaryItem *> *paymentSummaryItems;
//必填,三字母的 ISO 4217 貨幣代碼,比如人民幣為"CNY"
@property (nonatomic, copy) NSString *currencyCode;
可選設(shè)置的屬性
//表示必須需要填寫的訂單地址驳遵,默認(rèn)為PKAddressFieldNone(也就是什么也不寫),具體分類下面有介紹
@property (nonatomic, assign) PKAddressField requiredBillingAddressFields;
//必須的收貨人聯(lián)系方式山涡,默認(rèn)為PKAddressFieldNone
@property (nonatomic, assign) PKAddressField requiredShippingAddressFields;
typedef NS_OPTIONS(NSUInteger, PKAddressField) {
PKAddressFieldNone //默認(rèn)是不需要任何地址
PKAddressFieldPostalAddress // 一個完整的地址堤结,包含國家,郵政編碼佳鳖,省/區(qū),城市媒惕,街道系吩,姓名等
PKAddressFieldPhone //電話
PKAddressFieldEmail //郵箱
PKAddressFieldName NS_ENUM_AVAILABLE_IOS(8_3)//姓名
PKAddressFieldAll //包含以上所有信息
} NS_ENUM_AVAILABLE(NA, 8_0);
//賬單的地址,可能為nil,至于ABRecordRef為什么被廢棄妒蔚,是ABAddressBook在iOS9.0已經(jīng)不被推薦使用了
@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);
//送貨聯(lián)系地址穿挨,可能為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);
//存放送貨方式的數(shù)組,比如順豐肴盏,RILT..等
@property (nonatomic, copy, nullable) NSArray<PKShippingMethod *> *shippingMethods;
//用以保存所需信息的屬性科盛,可能為訂單或這書的唯一標(biāo)識符,它將被保存在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, //默認(rèn)為第三方發(fā)貨菜皂,比如順豐贞绵、圓通等..
PKShippingTypeDelivery, //賣家自己配送
PKShippingTypeStorePickup, //場家直送
PKShippingTypeServicePickup //買家自提
} NS_ENUM_AVAILABLE(NA, 8_3);
實例:PKPaymentRequest對象
- (PKPaymentRequest *)paymentRequest
{
PKPaymentRequest * payRequest = [PKPaymentRequest new];
//相關(guān)配置
_payNetworks = @[PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay,PKPaymentNetworkMasterCard];//支持的支付網(wǎng)絡(luò)
//證書identifier
payRequest.merchantIdentifier = @"merchant.com.yue.ApplePay";
//兩字母的 ISO 3166 國家代碼
payRequest.countryCode = @"CN";
//三字母的 ISO 4217 貨幣代碼
payRequest.currencyCode = @"CNY";
//支持的支付網(wǎng)絡(luò)
payRequest.supportedNetworks = _payNetworks;
//支持的銀行卡類型
payRequest.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityDebit | PKMerchantCapabilityCredit | PKMerchantCapabilityEMV;
//支付信息
payRequest.paymentSummaryItems = self.paymentSummaryItems;
//必須要有的賬單地址選項,默認(rèn)為None
payRequest.requiredBillingAddressFields = PKAddressFieldPostalAddress;
//必須要有的收貨人聯(lián)系方式選項,默認(rèn)為None
payRequest.requiredShippingAddressFields = PKAddressFieldPhone | PKAddressFieldPostalAddress;
//送貨方式,默認(rèn)為nil
payRequest.shippingMethods = [self shippingMethods];
//送貨類型
payRequest.shippingType = PKShippingTypeDelivery;
payRequest.applicationData = [@"我是RITL,來收費(fèi)啦" dataUsingEncoding:NSUTF8StringEncoding];
return payRequest;
}
支付的文本對象-PKPaymentSummaryItem
也就是在上圖中單價恍飘,數(shù)量等展示的選項榨崩,下面是開發(fā)文檔中的方法以及屬性:
/*便利構(gòu)造器*/
+ (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount;
+ (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount type:(PKPaymentSummaryItemType)type NS_AVAILABLE(NA, 9_0);
/*標(biāo)簽..比如單價、數(shù)量等..*/
@property (nonatomic, copy) NSString *label;
/*當(dāng)前標(biāo)簽的數(shù)組章母,與NSNumber類型相似母蛛,存儲浮點型的對象(與Java中的大整數(shù)和大浮點型數(shù)字是一樣的)*/
@property (nonatomic, copy) NSDecimalNumber *amount;
/*表示當(dāng)前ammount的類型*/
@property (nonatomic, assign) PKPaymentSummaryItemType type NS_AVAILABLE(NA, 9_0);
typedef NS_ENUM(NSUInteger, PKPaymentSummaryItemType) {
PKPaymentSummaryItemTypeFinal, //表示一個最終的數(shù)目,可以理解為一個確認(rèn)的數(shù)目,通常買東西都是固定的吧
PKPaymentSummaryItemTypePending //表示一個預(yù)計的數(shù)目乳怎,可變的彩郊,比如我們打出租的時候,價格不是固定的起步價吧?
} NS_ENUM_AVAILABLE(NA, 9_0);
實例:PKPaymentSummaryItem
- (NSArray<PKPaymentSummaryItem *> *)paymentSummaryItems
{
if (_paymentSummaryItems == nil)
{
//設(shè)置付款選項
PKPaymentSummaryItem * priceItem = [PKPaymentSummaryItem summaryItemWithLabel:@"單價" amount:[NSDecimalNumber decimalNumberWithString:self.priceTextField.text]];
PKPaymentSummaryItem * numberItem = [PKPaymentSummaryItem summaryItemWithLabel:@"數(shù)量" 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類恕出,但是多了兩個屬性:
//這個必須要寫,作為當(dāng)前方法的id
@property (nonatomic, copy, nullable) NSString *identifier;
//這個用來類似備注功能的屬性筷登,可以不寫
@property (nonatomic, copy, nullable) NSString *detail;
實例:PKShippingMethod
/// 送貨方式剃根,默認(rèn)為第一個
- (NSArray<PKShippingMethod *> *)shippingMethods
{
if (_shippingMethods == nil)
{
//設(shè)置收貨人送貨選項
PKShippingMethod * method1 = [PKShippingMethod shippingMethodWithLabel:@"順豐" amountString:@"20" identifier:@"shunfeng" detail:@"預(yù)計兩天后到達(dá)"];
PKShippingMethod * method2 = [PKShippingMethod shippingMethodWithLabel:@"圓通" amountString:@"18" identifier:@"yuantong" detail:@"預(yù)計一天后發(fā)貨"];
PKShippingMethod * method3 = [PKShippingMethod shippingMethodWithLabel:@"RITL" amountString:@"5" identifier:@"RITL" detail:@"估計就沒了.."];
_shippingMethods = @[method1,method2,method3];
//默認(rèn)
_payModel.shipMethod = method1;
}
return _shippingMethods;
}
驗證控制器協(xié)議-PKPaymentAuthorizationViewControllerDelegate
必須實現(xiàn)的協(xié)議方法
/*
* 進(jìn)行驗證并進(jìn)行回調(diào),并通過回調(diào)completion告知控制器是否成功,或失敗原因
* 與銀聯(lián)的交互應(yīng)該在此
*/
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didAuthorizePayment:(PKPayment *)payment
completion:(void (^)(PKPaymentAuthorizationStatus status))completion;
/* 驗證完畢或者直接點擊取消進(jìn)行的回調(diào) */
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller;
可選實現(xiàn)的協(xié)議方法
//在Touchid 或者 password(有的銀行還是需要密碼驗證的呢) 驗證之后的回調(diào)前方,點擊取消則不會響應(yīng)該方法
- (void)paymentAuthorizationViewControllerWillAuthorizePayment:(PKPaymentAuthorizationViewController *)controller NS_AVAILABLE_IOS(8_3)
{
}
//選中一個送貨方式后進(jìn)行的回調(diào)
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didSelectShippingMethod:(PKShippingMethod *)shippingMethod
completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray<PKPaymentSummaryItem *> *summaryItems))completion
{
//用來記錄送貨方式
_payModel.shipMethod = shippingMethod;
//進(jìn)行回調(diào)更新數(shù)據(jù)
completion(PKPaymentAuthorizationStatusSuccess,@[shippingMethod]);
}
//選中一個送貨聯(lián)系人
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didSelectShippingContact:(PKContact *)contact
completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray<PKShippingMethod *> *shippingMethods,
NSArray<PKPaymentSummaryItem *> *summaryItems))completion
{
//記錄配送聯(lián)系人
_payModel.contact = contact;
//進(jìn)行回調(diào)更新數(shù)據(jù)
completion(PKPaymentAuthorizationStatusSuccess,self.shippingMethods,self.paymentSummaryItems);
}
// 選中一個新的支付方式
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod
completion:(void (^)(NSArray<PKPaymentSummaryItem *> *summaryItems))completion
{
//記錄支付方式
_payModel.paymentMethod = paymentMethod;
//進(jìn)行回調(diào)更新數(shù)據(jù)
completion(self.paymentSummaryItems);
}
真正實現(xiàn)銀聯(lián)交互
說白了狈醉,Apple Pay只是作為了一個支付入口,真正實現(xiàn)支付作用的還是服務(wù)端惠险,至于如何真正的完成支付苗傅,請根據(jù)下面兩個鏈接進(jìn)行控件的下載以及CSR證書的配置(CSR證書如何使用,歡迎關(guān)注iOS開發(fā)------Apple Pay(證書配置篇)注冊App Pay RSA證書模塊)班巩,在此吐個槽渣慕,下面這兩個網(wǎng)址真TM難找...(為了避免好久之后網(wǎng)址不對,記錄一下當(dāng)前時間2016-08-24)
下載Apple Pay的開發(fā)控件抱慌,壓縮文件里面有詳細(xì)的規(guī)范pdf
https://open.unionpay.com/ajweb/help/file/techFile?productId=80
配置CSR的網(wǎng)址在下面逊桦,因為樓主沒法申請商戶賬號,所以想使用Apple Pay進(jìn)行支付的朋友們抑进,注冊賬號完畢后進(jìn)行注冊吧.
https://merchant.unionpay.com