GitHub 中文社区iOS 开发每天分享优质文章程序员

Apple Pay ---官方文档整理思路以及疑惑点

2017-07-30  本文已影响438人  李周

之前把Apple Pay的文档全部翻译了一遍,最近也是接触到了真实的项目开发。发现开发的过程还是和官方文档中的介绍有偏差,所以我会先将官方文档中的步骤有疑惑的地方记录下来,然后介绍在实际开发中的不同点。


1 Apple Pay 官方翻译文档

2 Apple Pay开发流程

3 Apple Pay实际开发


1 Apple Pay 官方翻译文档

官方与Apple Pay相关的文档主要包括 :
Apple Pay Programming Guide(官方编程指南):详细的讲解了在应用中的Apple Pay开发流程以及一定的解释

Apple Pay Programming Guide
Apple Pay官方编程指南(中文翻译)

PassKit (Apple Pay的支付框架):介绍了Apple Pay开发中所需要的类以及方法(已经有iOS 11的beta类和方法)

PassKit
PassKit(中文翻译)

2 Apple Pay开发流程

任何功能的开发都是需要在iTunes Connect中申请相关证书并且在Xcode 中将项目的Capabilities选项开启。以下是在代码开发的过程中的流程以及出现一些疑惑点:

步骤一 判断用户是否能使用Apple Pay支付

首先需要理解的是,用户不能使用Apple Pay支付有各种各种的原因,但是苹果为我们找到两类可控的原因:

1.设备是否支持,是否开启家长控制

[PKPaymentAuthorizationController canMakePayments];
[PKPaymentAuthorizationViewController canMakePayments];

2.是否在该网络下配置可供支付的卡

[PKPaymentAuthorizationController canMakePaymentsUsingNetworks:@[PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay,PKPaymentNetworkQuicPay]];
[PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:@[PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay,PKPaymentNetworkQuicPay]];

直观的看到上面的两个代码会出现三个疑惑点:

① PKPaymentAuthorizationController 和PKPaymentAuthorizationViewController 分别用在什么地方?

__WATCHOS_AVAILABLE(3.0) __IOS_AVAILABLE(10.0)
@interface PKPaymentAuthorizationController : NSObject
NS_CLASS_AVAILABLE_IOS(8_0)
@interface PKPaymentAuthorizationViewController : UIViewController

PKPaymentAuthorizationViewController和PKPaymentAuthorizationController扮演着相同的角色,而PKPaymentAuthorizationController并不依赖于UIKit框架。这就意味着AuthorizationController能用在视图控制器无法使用的地方(在watchOS或者 SiriKit extensions中)

② Apple Pay支持的Network包括哪些?

typedef NSString * PKPaymentNetwork NS_EXTENSIBLE_STRING_ENUM;
// American Express. 美国运通(外资信用卡)
PKPaymentNetwork const PKPaymentNetworkAmex  
//China Union Pay 中国银联
PKPaymentNetwork const PKPaymentNetworkChinaUnionPay
// Discover 发现卡(美国泛使)
PKPaymentNetwork const PKPaymentNetworkDiscover 
//加拿大Interac银行卡
PKPaymentNetwork const PKPaymentNetworkInterac 
// MasterCard 万事达
PKPaymentNetwork const PKPaymentNetworkMasterCard 
// Store credit and debit cards.信用卡和借记卡
PKPaymentNetwork const PKPaymentNetworkPrivateLabel 
// Visa.支付卡(全球)
PKPaymentNetwork const PKPaymentNetworkVisa 
//Japan Credit Bureau( 日本信用局)
PKPaymentNetwork const PKPaymentNetworkJCB 
// Suica 日本交通卡
PKPaymentNetwork const PKPaymentNetworkSuica 
//信用卡(日本)
PKPaymentNetwork const PKPaymentNetworkQuicPay 
(如果有人知道这两个的意思,可以告诉我)
PKPaymentNetwork const PKPaymentNetworkIDCredit 
PKPaymentNetwork const PKPaymentNetworkCarteBancaire 

③判断的顺序

对于应用而言,第一当然是判断当前设备是否支持,如果支持再判断在应用支持的网络中是否配置了相应的支付卡

 if ([ApplePayManager isApplePaySupport]) {
        if ([ApplePayManager isContainApplePayCard]) {
                NSLog(@"设备支持并且配置想要卡片");
        } else {
               NSLog(@"设备支持但在支持的网络下未配置卡片");
        }
    } else {
               NSLog(@"设备不支持或者家长控制");
    }

步骤二 根据判断结果显示不同Apple Pay按钮

对于设备硬件不支持或者家长控制的条件下,苹果官方推荐的做法是 ----- 不显示任何的按钮
而对于设备支持的条件下,苹果要求通过PKPaymentButton类进行设置.

NS_CLASS_AVAILABLE_IOS(8_3) @interface PKPaymentButton : UIButton
+ (instancetype)buttonWithType:(PKPaymentButtonType)buttonType style:(PKPaymentButtonStyle)buttonStyle;
- (instancetype)initWithPaymentButtonType:(PKPaymentButtonType)type paymentButtonStyle:(PKPaymentButtonStyle)style NS_AVAILABLE_IOS(9_0) NS_DESIGNATED_INITIALIZER;
@end

PKPaymentButton支付按钮由两个属性:

PKPaymentButtonType 按钮类型


PKPaymentButtonType 按钮类型

PKPaymentButtonStyle 按钮风格


PKPaymentButtonStyle 按钮风格

步骤三 点击按钮进行不同的处理

对于在未提供支持网络下的卡片时,苹果推荐进入wallet中设置并且会自动检测是否登录iCloud账号。
PKPassLibrary *library = [[PKPassLibrary alloc] init];
[library openPaymentSetup];

在这一步中会出现一个疑惑点:

很多人知道在iTunes connect中添加沙盒测试账号,但是如何添加一张可使用的支付卡?

Apple Pay Sandbox Testing

① 区域设置

参考官方文档,会发现能进行沙盒测试的区域并不包括中国。所以如果设备的地区设置为中国,设置中根本没有wallet&Apple Pay一栏:


测试区域并不包括中国

并且打开钱包应用,发现也无法设置Apple Pay:


钱包中并没有Apple Pay设置栏
所以,测试的第一步,设置为苹果支持测试的区域。
① 添加测试卡

设置好区域后,wallet&Apple Pay一栏会出现在设置界面中:


wallet&Apple Pay出现了

点击之后添加苹果推荐的测试卡号。但是我测试了好几十个都会出现以下的问题:


添加测试卡出错

去stack overflow上搜索答案的时候,发现有很多的人在不同区域都出现这样的问题。有些答案说要确认是测试账号或者重新登录再退出,但是试过都没有起作用,下面的答案可能有点解惑:
stack overflow解答

要使用真实的卡。苹果推荐不要使用开发者个人卡并且Apple Pay不支持国内的发卡行,所以使用该方法测试Apple Pay并不行的通。而且实际的开发中也并不会这么使用,具体的做法我会在后面说明。

对于在支持网络下已配置卡时,便能直接发送请求

PKPaymentRequest类主要的属性:

@interface PKPaymentRequest : NSObject
// 该平台支持的网络
+ (NSArray<PKPaymentNetwork> *)availableNetworks;
//开发者申请的商业标识符
@property (nonatomic, copy) NSString *merchantIdentifier;
// 两位的ISO城市代码
@property (nonatomic, copy) NSString *countryCode;
// 商家支持的网络
@property (nonatomic, copy) NSArray<PKPaymentNetwork> *supportedNetworks;
// 商家支持的支持处理网络
@property (nonatomic, assign) PKMerchantCapability merchantCapabilities;
//PKPaymentSummaryItem对象显示给用户,最后一项应该是总额
@property (nonatomic, copy) NSArray<PKPaymentSummaryItem *> *paymentSummaryItems;
//三位的ISO货币代码
@property (nonatomic, copy) NSString *currencyCode;
//账单地址,默认为PKAddressFieldNone.
@property (nonatomic, assign) PKAddressField requiredBillingAddressFields;
@property (nonatomic, strong, nullable) PKContact *billingContact;
//运输定制,默认为PKAddressFieldNone.
@property (nonatomic, assign) PKAddressField requiredShippingAddressFields;
@property (nonatomic, strong, nullable) PKContact *shippingContact 
//商家支持的运输方法
@property (nonatomic, copy, nullable) NSArray<PKShippingMethod *> *shippingMethods;
//运输的显示模式,默认为PKShippingTypeShipping
@property (nonatomic, assign) PKShippingType shippingType 
①举例而言,当用户想要购买一件300块打折50元的衬衫时:
 //shirt 300元 折扣为50元
        NSDecimalNumber *shirt = [NSDecimalNumber decimalNumberWithMantissa:300 exponent:0 isNegative:NO];
        NSDecimalNumber *discount = [NSDecimalNumber decimalNumberWithMantissa:50 exponent:0 isNegative:YES];
        NSDecimalNumber *total = [shirt decimalNumberByAdding:discount];
        
        PKPaymentSummaryItem *shirtItem = [PKPaymentSummaryItem summaryItemWithLabel:@"shirt" amount:shirt];
        PKPaymentSummaryItem *shirtDiscount = [PKPaymentSummaryItem summaryItemWithLabel:@"discount" amount:discount];
        PKPaymentSummaryItem *totalItem = [PKPaymentSummaryItem summaryItemWithLabel:@"李周" amount:total type:PKPaymentSummaryItemTypeFinal];
        
        PKPaymentRequest *request = [[PKPaymentRequest alloc] init];
        request.paymentSummaryItems = @[shirtItem,shirtDiscount,totalItem];
        request.supportedNetworks = @[PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay,PKPaymentNetworkQuicPay];
        request.currencyCode = @"CNY";
        request.countryCode = @"CN";
        request.merchantIdentifier = @"merchant.com.lizhou.Payment";
        request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV;

上面的例子很容易理解,但是一眼看过去对merchantCapabilities属性有疑惑点:该值设置的到底是什么?

该属性设置的是交易处理协议,苹果强调的是你必须支持3-D安全协议;可选是否支持EMV协议(国内要选择支持)。

// 3-D Secure protocol.  (国外安全支付模式)Visa的
 PKMerchantCapability3DS
//EMV protocol.协议(EMV标准,国际三大银行卡组织同时发起制定的银行卡从磁条卡向智能IC卡转移的技术标准)
 PKMerchantCapabilityEMV
// Support for credit cards.支持信用卡
 PKMerchantCapabilityCredit
// Support for debit cards.支持借记卡
 PKMerchantCapabilityDebit
效果图
②添加运输的信息

如果商家要求设置运输信息,包括姓名、联系电话、地址:

 request.requiredShippingAddressFields = PKAddressFieldPostalAddress | PKAddressFieldPhone | PKAddressFieldName;

如果用户并没有设置过运输要求信息,则会出现以下界面:


效果图

当然,苹果推荐在出现支付界面前设置好一切信息,不要让用户做一些别的事情,以免取消支付。

设置商家支持的运输方式:

  request.requiredShippingAddressFields = PKAddressFieldPostalAddress | PKAddressFieldPhone | PKAddressFieldName;
        PKShippingMethod *freeMethod = [PKShippingMethod summaryItemWithLabel:@"包邮" amount:[NSDecimalNumber zero]];
        freeMethod.identifier = @"Free";
        freeMethod.detail = @"最慢的咯";
        PKShippingMethod *YunMethod = [PKShippingMethod summaryItemWithLabel:@"韵达快递" amount:[NSDecimalNumber decimalNumberWithMantissa:10 exponent:0 isNegative:NO]];
        YunMethod.detail = @"2-3天哦";
        YunMethod.identifier = @"YunDa";
        request.shippingMethods = @[freeMethod,YunMethod];
商家设置运输方式效果图

最后介绍在弹出的支付弹窗中的一些操作回调方法:

//在支付验证前,但是在用户输入密码或者Touch ID前
- (void)paymentAuthorizationViewControllerWillAuthorizePayment:(PKPaymentAuthorizationViewController *)controller
//选择送货地址回调
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                   didSelectShippingMethod:(PKShippingMethod *)shippingMethod
                                completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray<PKPaymentSummaryItem *> *summaryItems))completion;
//选择送货方式回调
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                  didSelectShippingContact:(PKContact *)contact
                                completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray<PKShippingMethod *> *shippingMethods,
                                                     NSArray<PKPaymentSummaryItem *> *summaryItems))completion 
//选择支付卡回调
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                    didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod
                                completion:(void (^)(NSArray<PKPaymentSummaryItem *> *summaryItems))completion 
//付款成功,将数据发送给你的服务器
- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                        didAuthorizePayment:(PKPayment *)payment
                                 completion:(void (^)(PKPaymentAuthorizationStatus))completion
//交易结束
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller;

3 Apple Pay实际开发

其实看了上面官网的文档之后,我一直很好奇的是:

钱到底是怎么没的?不需要和服务器进行沟通吗?

后来才知道,Apple Pay只是一种支付的工具,并不参与到支付的流程中,也就是不会收取任何的费用。所以如果在国内需要使用银行卡进行Apple Pay的支付,可以去银联的官方进行产品签约,收取的手续费用当然是依据你们公司与银联的沟通情况。
并且银联SDK内部直接对Apple Pay进行封装了,所以整个流程就是:
①应用内 ->订单相关数据 ->服务器 ->封装成订单 ->银联
②银联记录提供的订单并生成标识订单的TN号返回给服务器,发送给应用。
③应用调用银联SDK中的方法将TN号回传给银联,银联会将结果信息回传

所以:
1 在银联的SDK方法中很容易发现:如何在测试环境和生成环境中切换
2 服务器向银联进行下单返回TN的时候还未进行支付,直到应用调用SDK中的方法才进行真正的支付
3 银联对Apple pay支付进行了很强的封装,所以直接调用银联的返回结果状态进行判断即可


其实之前老说Apple Pay、Apple Pay的,但是现在才能很明白其中的机制,才知道苹果提供的只是支付工具。所以在实际开发的时候一定要和相应的机构签约,而不是去想:Apple pay本身到底如何ba

上一篇下一篇

猜你喜欢

热点阅读