iOS开发------Apple Pay(PassKit.framework篇)

俗话说凡事应有始有终,所以还是决定趁空余时间将这篇Apple Pay(PassKit.framework篇)补充完整,万一有相同疑问的小伙伴呢,好有个参考,也不枉花费的时间。说实话,网上其实有很多介绍Apple Pay的文章,但总是感觉不太详细,在探索的过程中没有给我太大的帮助,便把更多的时间执着于开发文档,由于楼主的英文能力不是很强,也算是花了不少的时间。如果该文有什么错误或者误解,请指正,3Q。

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

启用Apple Pay

在配置完所有的证书之后,首先记得要在Xcode的项目中启用Apple Pay模块。具体位置在TARGET->Capablitiles->Apple Pay,如果配置好了Merchant IDs,那就等一小会就会自动刷新,只需要打上勾即可,如图。

支付验证控制器 -PKPaymentAuthorizationViewController

顾名思义,它就是一个支付验证的控制器,上图中模态弹出的控制器其实就是PKPaymentAuthorizationViewController.

类方法-Function

下面是开发文档中的方法,并通过我的个人理解做的介绍:

//验证是否能够进行NFC支付操作--建议模态弹出控制器的时候验证一下
+ (BOOL)canMakePayments;
//验证是否能够支持特定的支付途径,它的定义存在"PKConstants.h"文件中,下面会介绍一下
+ (BOOL)canMakePaymentsUsingNetworks:(NSArray *)supportedNetworks;
//iOS9_0之后才有的方法,不过个人觉得不太需要担心,毕竟银联支持Apple Pay是iOS9_2之后的
//出了能够验证特定的支付途径之外,还可以验证支付卡的类型
+ (BOOL)canMakePaymentsUsingNetworks:(NSArray *)supportedNetworks                         capabilities:(PKMerchantCapability)capabilties NS_AVAILABLE_IOS(9_0);//代理属性,对应的协议

后面也会有记录

@property (nonatomic, assign, nullable) id

 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 *supportedNetworks;//必填,支持的Capabilties(支付卡类型),具体值上面以列出,可以通过|来支持多种类型@property(nonatomic,assign) PKMerchantCapability merchantCapabilities;//必填,存放PKPaymentSummaryItem(支付信息)的数组,并且最后一个必须为总价格,后面会有介绍@property(nonatomic, copy)NSArray *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

 *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

 *)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类,但是多了两个属性:

@property (nonatomic, copy, nullable) NSString *identifier;//这个用来类似备注功能的属性,可以不写
@property (nonatomic, copy, nullable) NSString *detail;
实例:PKShippingMethod
/// 送货方式,默认为第一个
- (NSArray

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

 *summaryItems))completion {

//用来记录送货方式
_payModel.shipMethod = shippingMethod;    //进行回调更新数据
completion(PKPaymentAuthorizationStatusSuccess,@[shippingMethod]);
}
//选中一个送货联系人
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller                   didSelectShippingContact:(PKContact *)contact                                 completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray

 *shippingMethods,                                                     NSArray

 *summaryItems))completion {

//记录配送联系人
_payModel.contact = contact;    //进行回调更新数据
completion(PKPaymentAuthorizationStatusSuccess,self.shippingMethods,self.paymentSummaryItems);
}
// 选中一个新的支付方式
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller                     didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod                                 completion:(void (^)(NSArray

 *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 

文/作者:RITL

博客地址:http://blog.csdn.net/runintolove/article/details/52217360 



欢迎关注微信公众号:iOS面向编码

QQ群:427763454

欢迎你的投稿,展示的你的技术文章:812920365@qq.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容