Apple Pay运行环境:iPhone6以上设备,操作系统最低iOS9.0以上,部分信息设置需要iOS9.2以上。目前还不支持企业证书添加。

环境搭建好后可以在模拟器上面运行,xcode7.2.1+iPhone6SP9.2系统下,系统会绑定几种虚拟的银行卡,和几个联系人,方便调试,支付也不会发生真实的付款,真的很方便。

准备工作

在接入Apple Pay之前,首先要申请MerchantID及对应证书。(申请MerchantID及对应证书详细图文教程

工程设置

  • bundleID设置

Capability中启用Apple Pay权限,并选择merchantID。

之后项目会多一个Applepay的配置文件ApplePayYasin.entitlements

  • 需要引用的库

Xcode7.0以上不需要再手动添加需要引用的库了,只需要导入头文件就可以了

1
2
3
#import <passkit passkit.h="">                                 //用户绑定的银行卡信息
#import <passkit pkpaymentauthorizationviewcontroller.h="">    //Apple pay的展示控件
#import <addressbook addressbook.h="">                         //用户联系信息相关</addressbook></passkit></passkit>
  • 设备Applepay权限检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (![PKPaymentAuthorizationViewController class]) {
        //PKPaymentAuthorizationViewController需iOS8.0以上支持
        NSLog(@"操作系统不支持ApplePay,请升级至9.0以上版本,且iPhone6以上设备才支持");
        return;
    }
    //检查当前设备是否可以支付
    if (![PKPaymentAuthorizationViewController canMakePayments]) {
        //支付需iOS9.0以上支持
        NSLog(@"设备不支持ApplePay,请升级至9.0以上版本,且iPhone6以上设备才支持");
        return;
    }
    //检查用户是否可进行某种卡的支付,是否支持Amex、MasterCard、Visa与银联四种卡,根据自己项目的需要进行检测
    NSArray *supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard,PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay];
    if (![PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:supportedNetworks]) {
        NSLog(@"没有绑定支付卡");
        return;
    }

创建支付请求PKPaymentRequest

  • 初始化PKPaymentRequest

这里需要注意RMB的币种代码是CNY

1
2
3
4
5
6
7
//设置币种、国家码及merchant标识符等基本信息
  PKPaymentRequest *payRequest = [[PKPaymentRequest alloc]init];
  payRequest.countryCode = @"CN";     //国家代码
  payRequest.currencyCode = @"CNY";       //RMB的币种代码
  payRequest.merchantIdentifier = @"merchant.ApplePayDemoYasin";  //申请的merchantID
  payRequest.supportedNetworks = supportedNetworks;   //用户可进行支付的银行卡
  payRequest.merchantCapabilities = PKMerchantCapability3DS|PKMerchantCapabilityEMV;      //设置支持的交易处理协议,3DS必须支持,EMV为可选,目前国内的话还是使用两者吧
  • 设置发票配送信息和货物配送地址信息,用户设置后可以通过代理回调代理获取信息的更新

1
2
3
4
5
// payRequest.requiredBillingAddressFields = PKAddressFieldEmail;   
//如果需要邮寄账单可以选择进行设置,默认PKAddressFieldNone(不邮寄账单)
//楼主感觉账单邮寄地址可以事先让用户选择是否需要,否则会增加客户的输入麻烦度,体验不好,
  payRequest.requiredShippingAddressFields = PKAddressFieldPostalAddress|PKAddressFieldPhone|PKAddressFieldName;
  //送货地址信息,这里设置需要地址和联系方式和姓名,如果需要进行设置,默认PKAddressFieldNone(没有送货地址)

送货信息页面展示

设置货物的配送方式,不需要不配置

1
2
3
4
5
6
7
8
9
10
//设置两种配送方式
  PKShippingMethod *freeShipping = [PKShippingMethod summaryItemWithLabel:@"包邮" amount:[NSDecimalNumber zero]];
  freeShipping.identifier = @"freeshipping";
  freeShipping.detail = @"6-8 天 送达";
   
  PKShippingMethod *expressShipping = [PKShippingMethod summaryItemWithLabel:@"极速送达" amount:[NSDecimalNumber decimalNumberWithString:@"10.00"]];
  expressShipping.identifier = @"expressshipping";
  expressShipping.detail = @"2-3 小时 送达";
   
  payRequest.shippingMethods = @[freeShipping, expressShipping];

  • 账单信息的设置

每条账单的设置

账单列表使用PKPaymentSummaryItem添加描述和价格,价格使用NSDecimalNumber。

PKPaymentSummaryItem初始化:

label为商品名字或者是描述,amount为商品价格,折扣为负数,type为该条账单为最终价格还是估算价格(比如出租车价格预估)

1
2
+ (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount;
+ (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount type:(PKPaymentSummaryItemType)type NS_AVAILABLE(NA, 9_0);

NSDecimalNumber初始化:

NSDecimalNumber可以使用数字初始化,也可以使用字符串。

使用方法请移步我写的NSDecimalNumber--十进制数

添加账单列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO];   //12.75
PKPaymentSummaryItem *subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"商品价格" amount:subtotalAmount];
 
NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithString:@"-12.74"];      //-12.74
PKPaymentSummaryItem *discount = [PKPaymentSummaryItem summaryItemWithLabel:@"优惠折扣" amount:discountAmount];
 
NSDecimalNumber *methodsAmount = [NSDecimalNumber zero];
PKPaymentSummaryItem *methods = [PKPaymentSummaryItem summaryItemWithLabel:@"包邮" amount:methodsAmount];
 
NSDecimalNumber *totalAmount = [NSDecimalNumber zero];
totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount];
totalAmount = [totalAmount decimalNumberByAdding:discountAmount];
totalAmount = [totalAmount decimalNumberByAdding:methodsAmount];
PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"Yasin" amount:totalAmount];  //最后这个是支付给谁。哈哈,快支付给我
 
summaryItems = [NSMutableArray arrayWithArray:@[subtotal, discount, methods, total]];
//summaryItems为账单列表,类型是 NSMutableArray,这里设置成成员变量,在后续的代理回调中可以进行支付金额的调整。
payRequest.paymentSummaryItems = summaryItems;

显示购物信息并进行支付

1
2
3
4
//ApplePay控件
    PKPaymentAuthorizationViewController *view = [[PKPaymentAuthorizationViewController alloc]initWithPaymentRequest:payRequest];
    view.delegate = self;
    [self presentViewController:view animated:YES completion:nil];

PKPaymentAuthorizationViewControllerDelegate代理

  • 这里还有两个类要介绍

PKPayment 支付成功信息

1
2
3
4
5
PKPaymentToken *payToken = payment.token;
//支付凭据,发给服务端进行验证支付是否真实有效
PKContact *billingContact = payment.billingContact;     //账单信息
PKContact *shippingContact = payment.shippingContact;   //送货信息
PKContact *shippingMethod = payment.shippingMethod;     //送货方式

PKContact 联系人信息

1
2
3
4
5
NSPersonNameComponents *name = contact.name;                //联系人姓名
CNPostalAddress *postalAddress = contact.postalAddress;     //联系人地址
NSString *emailAddress = contact.emailAddress;              //联系人邮箱
CNPhoneNumber *phoneNumber = contact.phoneNumber;           //联系人手机
NSString *supplementarySubLocality = contact.supplementarySubLocality;  //补充信息,地址详细描述,其他备注等等,iOS9.2及以上才有
  • 代理说明

送货地址回调

1
2
3
4
5
6
7
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                didSelectShippingContact:(PKContact *)contact
                              completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<pkshippingmethod *> * _Nonnull, NSArray<pkpaymentsummaryitem *> * _Nonnull))completion{
  //contact送货地址信息,PKContact类型
  //送货信息选择回调,如果需要根据送货地址调整送货方式,比如普通地区包邮+极速配送,偏远地区只有付费普通配送,进行支付金额重新计算,可以实现该代理,返回给系统:shippingMethods配送方式,summaryItems账单列表,如果不支持该送货信息返回想要的PKPaymentAuthorizationStatus
  completion(PKPaymentAuthorizationStatusSuccess, shippingMethods, summaryItems);
}</pkpaymentsummaryitem *></pkshippingmethod *>

送货方式回调

1
2
3
4
5
6
7
8
9
10
11
12
13
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                 didSelectShippingMethod:(PKShippingMethod *)shippingMethod
                              completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<pkpaymentsummaryitem *> * _Nonnull))completion{
  //配送方式回调,如果需要根据不同的送货方式进行支付金额的调整,比如包邮和付费加速配送,可以实现该代理
  PKShippingMethod *oldShippingMethod = [summaryItems objectAtIndex:2];
  PKPaymentSummaryItem *total = [summaryItems lastObject];
  total.amount = [total.amount decimalNumberBySubtracting:oldShippingMethod.amount];
  total.amount = [total.amount decimalNumberByAdding:shippingMethod.amount];
  [summaryItems replaceObjectAtIndex:2 withObject:shippingMethod];
  [summaryItems replaceObjectAtIndex:3 withObject:total];
   
  completion(PKPaymentAuthorizationStatusSuccess, summaryItems);
}</pkpaymentsummaryitem *>

支付卡选择回调

1
2
3
4
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod completion:(void (^)(NSArray<pkpaymentsummaryitem *> * _Nonnull))completion{
  //支付银行卡回调,如果需要根据不同的银行调整付费金额,可以实现该代理
  completion(summaryItems);
}</pkpaymentsummaryitem *>

送货地址回调,已弃用

1
2
3
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectShippingAddress:(ABRecordRef)address completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<pkshippingmethod *> * _Nonnull, NSArray<pkpaymentsummaryitem *> * _Nonnull))completion{
  //送货地址回调,已弃用
}</pkpaymentsummaryitem *></pkshippingmethod *>

付款成功苹果服务器返回信息回调,做服务器验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                     didAuthorizePayment:(PKPayment *)payment
                              completion:(void (^)(PKPaymentAuthorizationStatus status))completion {
  PKPaymentToken *payToken = payment.token;
  //支付凭据,发给服务端进行验证支付是否真实有效
  PKContact *billingContact = payment.billingContact;     //账单信息
  PKContact *shippingContact = payment.shippingContact;   //送货信息
  PKContact *shippingMethod = payment.shippingMethod;     //送货方式
  //等待服务器返回结果后再进行系统block调用
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
      //模拟服务器通信
      completion(PKPaymentAuthorizationStatusSuccess);
  });
}

支付完成回调

1
2
3
-(void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller{
  [controller dismissViewControllerAnimated:YES completion:nil];
}

Apple Pay的更多相关文章

  1. Apple Pay 初探

    Apple Pay 一.概述 1.支付方式:Touch ID/ Passcode 2.设备要求:iPhone6以上(iphone:线上/线下 ipad:线上 watch:线下) 3.系统要求:iOS8 ...

  2. 【转】iOS开发 -- Apple Pay

    技术博客原地址:http://www.cnblogs.com/dashunzi/p/ApplePay.html#top 原技术博客中有源码和视频,有感兴趣的朋友可以研究一下! 一.什么是Apple P ...

  3. Apple Pay的快速实现

    一.在Apple开发者中心配置 AppleID 和 Merchant IDs 二.配置好证书后在Xcode中开启Apple Pay 三.代码实现 3.1 判断是否支持Apple Pay,如果支持又将支 ...

  4. 开发apple pay碰到的问题总结

    本来想简单总结一下Apple Pay 开发过程中的几个问题, 结果被下面这篇文章全碰上了, 干脆全文转载, 作者对相关资源整理得比较详细, 比较有参考价值 总的来说, 我们做过 APNs 推送的话, ...

  5. iOS Apple Pay

    iOS 苹果支付 需要证书支持支付功能 targets 打开支付功能按钮 //ApplePay#import <PassKit/PassKit.h>                     ...

  6. iOS开发 Apple Pay

    一.什么是Apple Pay? 1. 概念 Apple Pay,简单来说, 就是一种移动支付方式.通过Touch ID/ Passcode,用户可使用存储在iPhone 6, 6p等设备上的信用卡和借 ...

  7. Apple Pay(转)

    Apple Pay 是在 iOS 8 中第一次被介绍,它可以为你的应用中的实体商品和服务,提供简单.安全.私密的支付方式.它使得用户支付起来非常简便,只需按一下指纹就可以授权进行交易. Apple P ...

  8. 集成 Apple Pay

    作者感言 在中秋过后终于把国内的三大支付平台SDK集成都搞定了, 现在我们终于可以来研究Apple自家的支付Apple Pay最后:如果你有更好的建议或者对这篇文章有不满的地方, 请联系我, 我会参考 ...

  9. Apple Pay强势来袭,开发者应做的事情

    "iOS8.1就已经有这个功能了,只是木有现在这么的火,现在的趋势是要火的节奏,因此很多电商平台B2B,P2P,C2C,X2X都有可能需要这个屌丝的付款功能了,在此简单的研究一下." ...

随机推荐

  1. bzoj4358: permu

    莫队算法,用线段树维护最长连续1,复杂度O(nsqrt(m)logn) 刚开始TLE了,看了claris大爷的blog说是kd-tree,然而并不会kd-tree…… 然后就打算弃疗了...弃疗之前加 ...

  2. u Calculate e阶乘相加求和问题

    问题: (n < 10)写个算法 回答: 方法一: #include<stdio.h>  int main()  {      int f[10]={1,1,2,6,24,120,7 ...

  3. Oracle 数据库对象

    数据库对象是数据库的组成部分,常常用CREATE命令进行创建,可以使用ALTER命令修改,用DROP执行删除操作.前面已经接触过的数据库对象有表.用户等. 今天将学习更多的Oracle数据库对象: 同 ...

  4. AngularJs $templateCache 和 $templateRequest 模板缓存

    $templateCache 第一次使用模板,它被加载到模板缓存中,以便快速检索.你可以直接将模板标签加载到缓存中,或者通过$templateCache服务. 通过script标签: <scri ...

  5. 软件工程个人作业 - week1

    <构建之法>阅读疑惑: 如何寻找开发效率和性能的均衡点?显然开发效率强调封装,重视代码重用.但是遗憾的是代码重用往往泛化了数据特征,降低了效率. 如何“公平”分配工作?尤其是团队中人员参差 ...

  6. JavaWeb学习总结-07 Filter 学习和使用

    一 Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态 ...

  7. Nginx系列5之让Nginx支持HTTP1.1

    preface nginx在反向代理HTTP协议的时候,默认使用的是HTTP1.0去向后端服务器获取响应的内容后在返回给客户端. HTTP1.0和HTTP1.1的一个不同之处就是,HTTP1.0不支持 ...

  8. angular ui-router 缓存问题

    在个别情况下 $state.go()路径和参数完全相同的时候页面因为缓存问题可以直接跳转,但是不能重新获取数据 通过路由参数可以解决 路由 .state('app.***.***', { url: ' ...

  9. js009-客户端检测

    js009-客户端检测 本章内容: 1.使用能力检测 2.用户代理检测的历史 3.选择检测方式 一般不使用客户端检测. 9.1 能力检测 也称特性检测.基本模式如下: if(object.proper ...

  10. winform 窗体传值

    在Form1中:我们要把一个文本传递给Form2窗体,假定为passText               public string passText               {          ...