美文网首页iOSiOS 艾欧艾斯ApplePay Wallet
iOS开发------Apple Pay(PassKit.fra

iOS开发------Apple Pay(PassKit.fra

作者: RITL | 来源:发表于2016-08-25 09:48 被阅读655次

    由于项目突赶进度,从上次发布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

    相关文章

      网友评论

        本文标题:iOS开发------Apple Pay(PassKit.fra

        本文链接:https://www.haomeiwen.com/subject/yjoosttx.html