apple pay代码实现
一、代码实现之前先配置证书和Merchant ID :
具体证书操作看:http://blog.csdn.net/songchunmin_/article/details/51543356
支持 apple pay的设备:http://blog.csdn.net/songchunmin_/article/details/51535668
demo地址:https://github.com/songchunmin/PayDemo
二、具体实现
/* 判定用户是否能够支付,在创建支付请求之前,要首先通过调用PKPaymentAuthorizationViewController 类里的canMakePaymentsUsingNetworks:方法来判断用户是否能够使用你提供的支付网络进行支付。如果要判断用户的硬件是否支持Apple Pay或者是否因为家长控制而不能支付,请使用canMakePayments 方法。如果用户不能进行支付,那就不要显示支付按钮,相应的应该退回到其它支付方式。*/if([PKPaymentAuthorizationViewController canMakePayments]) {NSLog(@"Woo! Can make payments!");PKPaymentRequest *request = [[PKPaymentRequest alloc] init];// PKPaymentSummaryItem *widget1 = [PKPaymentSummaryItem summaryItemWithLabel:@"娃哈哈"amount:[NSDecimalNumber decimalNumberWithString:@"0.01"]type:PKPaymentSummaryItemTypeFinal];PKPaymentSummaryItem *widget2 = [PKPaymentSummaryItem summaryItemWithLabel:@"鲜牛奶"amount:[NSDecimalNumber decimalNumberWithString:@"0.01"]];PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"Grand Total"amount:[NSDecimalNumber decimalNumberWithString:@"0.02"]];//数组中,最后的对象是总价。request.paymentSummaryItems = @[widget1, widget2, total];//国家--一定要填写正确,如果不知道的话,随便输入,控制台会列举所有的出来,request.countryCode = @"CN";//货币单位需要使用- 人民币request.currencyCode = @"CNY";//Wallet所绑定的卡的类型, 银联记得加上,我记得在配置证书那里选项,是否支持中国境内(大概意思),这里不加PKPaymentNetworkChinaUnionPay直接Crash,估计和这个有关。。。request.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay];request.merchantIdentifier = @"merchant.com.scm.PayDemo";//通过指定merchantCapabilities属性来指定你支持的支付处理标准,3DS支付方式是必须支持的,EMV方式是可选的。request.merchantCapabilities = PKMerchantCapabilityEMV;//设置后,如果用户之前没有填写过,那么会要求用户必须填写才能够使用Apple Pay
// request.requiredShippingAddressFields = PKAddressFieldPostalAddress | PKAddressFieldPhone | PKAddressFieldEmail | PKAddressFieldName;//显示支付信息的控制器self.paymentPane = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];self.paymentPane.delegate = self;[self presentViewController:_paymentPane animated:TRUE completion:nil];} else {NSLog(@"This device cannot make payments");}
}/*** 用户发送付款请求后会调用该方法。在这个方法中发送相关的支付信息到你的服务器,最后通过服务器来处理。如果服务期处理成功,* 那么需要调用 completion 的block 并且传入 PKPaymentAuthorizationStatusSuccess 的标记即可。* 如果服务器处理不成功,那么传一个其他的标记就可以了*/
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controllerdidAuthorizePayment:(PKPayment *)paymentcompletion:(void (^)(PKPaymentAuthorizationStatus status))completion
{NSLog(@"Payment was authorized: %@", payment);// do an async call to the server to complete the payment.// See PKPayment class reference for object parameters that can be passedBOOL asyncSuccessful = FALSE;// When the async call is done, send the callback.// Available cases are:// PKPaymentAuthorizationStatusSuccess, // Merchant auth'd (or expects to auth) the transaction successfully.// PKPaymentAuthorizationStatusFailure, // Merchant failed to auth the transaction.//// PKPaymentAuthorizationStatusInvalidBillingPostalAddress, // Merchant refuses service to this billing address.// PKPaymentAuthorizationStatusInvalidShippingPostalAddress, // Merchant refuses service to this shipping address.// PKPaymentAuthorizationStatusInvalidShippingContact // Supplied contact information is insufficient.if(asyncSuccessful) {completion(PKPaymentAuthorizationStatusSuccess);// do something to let the user know the statusNSLog(@"Payment was successful");// [Crittercism endTransaction:@"checkout"];} else {completion(PKPaymentAuthorizationStatusFailure);// do something to let the user know the statusNSLog(@"Payment was unsuccessful");// [Crittercism failTransaction:@"checkout"];}
三、注意事项(参考别人的,原博客: http://www.open-open.com/lib/view/open1422324034345.html)
创建支付请求
支付请求是PKPaymentRequest类的实例,它的组成部分包括一个用来表示将要购买的项目的摘要,一个可用的配送方式列表,一个表示用户需要提供的配送信息的描述,以及一些商家和支付平台的信息。
判定用户是否能够支付
在创建支付请求之前,要首先通过调用PKPaymentAuthorizationViewController 类里的canMakePaymentsUsingNetworks:方法来判断用户是否能够使用你提供的支付网络进行支付。如果要判断用户的硬件是否支持Apple Pay或者是否因为家长控制而不能支付,请使用canMakePayments 方法。
如果用户不能进行支付,那就不要显示支付按钮,相应的应该退回到其它支付方式。
支付请求包含货币和地区信息
所有的汇总金额应该使用同一种货币,货币的信息可使用PKPaymentRequest类的currencyCode属性进行指定。像"USD"这样,使用3个字符格式的ISO货币编码。
一个支付请求里的国家代码表示了这次购买发生的国家或者将要在这个国家处理这次支付。像"US"这样,使用2个字符格式的ISO国家编码。
在支付请求里指定的商用ID必须匹配应用中指定的商用ID列表之一。
request.currencyCode = @"USD"; request.countryCode = @"US"; request.merchantIdentifier = @"merchant.com.example";
支付请求包含一个支付摘要项目的列表
支付摘要项目,属于PKPaymentSummaryItem 类,描述了支付请求的不同部分。在一个支付请求里不要使用太多的摘要项目---典型的项目像比如小计金额、折扣信息、配送信息、含税信息以及总计金额等。如果你想要提供更详细的支付项目列表,可以在你应用的其它地方提供。
每一个摘要项目会有一个标签和数额,就像在代码列表3-1中显示的那样。标签文本是一个用户可阅读的摘要项目描述信息,数额是相对应的支付数额。在一个支付请求中所有的数额都要使用在这个请求中指定的货币。对于折扣或优惠券,则需要把数额设成负数。
Listing 3-1创建支付项目
// 12.75 subtotal NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]; self.subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"Subtotal" amount:subtotalAmount];// 2.00 discount NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithMantissa:200 exponent:-2 isNegative:YES]; self.discount = [PKPaymentSummaryItem summaryItemWithLabel:@"Discount" amount:discountAmount];
注意
这里使用NSDecimalNumber类来存储摘要项目的数额,它是一个以10为底数的数值。可以使用指定尾数和指数的方式(像代码中那样)来创建这个类的实例,也可以通过指定字符串和locale来实例化,字符串指定了相应的数值。这里总是使用以10为底数的数值来做财务计算--例如当需要计算5%折扣掉的金额时。
尽管有时使用其它的计数方法更方便,但是像float或者Double这样的IEEE浮点数类型是不适合作财务计算的,这些数据类型使用的是以2为底数的数值表示方法,这就表示有一些十进制数值不能准确得被表示--例如0.42必须以0.41999这样的循环小数来近似表示,而这种近似表示常常会造成财务计算的错误结果。
在这个摘要项目列表中的最后一个是总计金额。这个金额是通过把所有其它金额相加而得到。总计的显示方法和其它的摘要项目不同:应该使用你公司的名称做为其标签,使用所有其它项目的金额总和做为金额。使用paymentSummaryItems 属性将这些摘要项目加入支付请求。
// 10.75 grand total NSDecimalNumber *totalAmount = [NSDecimalNumber zero]; totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount]; totalAmount = [totalAmount decimalNumberByAdding:discountAmount]; self.total = [PKPaymentSummaryItem summaryItemWithLabel:@"My Company Name" amount:totalAmount]; self.summaryItems = @[self.subtotal, self.discount, self.total]; request.paymentSummaryItems = self.summaryItems;
配送方式是一种特殊的摘要项目
对于每一种可用的配送方式创建一个PKShippingMethod的实例。就像其它支付摘要项目一样,配送方式包含用户易于辨别的标签,比如"标准配送"或者"第二天配送",还有一个金额来表示配送费用。与其它摘要项目不同的是,配送方式还有一个detail属性--像"7月29日到达"或者"24小时之内配送"等--可以用来解释各个配送方式之间的区别。
使用identifier属性来在代理方法中区分不同的配送方式,这个属性只会在你的应用内使用--框架看不到这个属性,并且它也不会出现在UI中。在创建配送方式时为其分配一个独一无二的标识符。为了方便调试,可使用文本缩写,比如"discount", "standard", 或者 "next-day".
有一些配送方式在某些地区可能不适用,或者有不同的价格,你可以在用户选择配送地址或配送方式的代理方法时更新这些信息,就像Your Delegate Updates Shipping Methods and Costs描述的一样。
指定你支持的支付方式
通过在supportedNetworks属性中填入字符串常量数组来指定你支持的支付网络。通过指定merchantCapabilities属性来指定你支持的支付处理标准,3DS支付方式是必须支持的,EMV方式是可选的。
商家支持的支付处理标准使用标识位来进行组合,像下面这样:
request.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa]; // Supports 3DS only request.merchantCapabilities = PKMerchantCapability3DS; // Supports both 3DS and EMV request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV;
指示所需配送信息和账单信息
通过填充 requiredBillingAddressFields 和 requiredShippingAddressFields属性来指定所需账单信息和配送地址信息。当你显示一个视图控制器时,它会提示用户输入所需内容。这些字段常量可以像下面这样进行组合来设置这些属性:
request.requiredBillingAddressFields = PKAddressFieldEmail; request.requiredBillingAddressFields = PKAddressFieldEmail | PKAddressFieldPostalAddress;
如果你已经有了用户的账单和配送信息,可以直接在支付请求中使用它们。但是尽管Apple Pay默认使用了这些信息,用户仍然可以在授权支付的过程中修改这些信息。
ABRecordRef record = ABPersonCreate(); CFErrorRef error; BOOL success; success = ABRecordSetValue(record, kABPersonFirstNameProperty, @"John", &error); if (!success) { /* ... handle error ... */ } success = ABRecordSetValue(record, kABPersonLastNameProperty, @"Appleseed", &error); if (!success) { /* ... handle error ... */ } ABMultiValueRef shippingAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType); NSDictionary *addressDictionary = @{ (NSString *) kABPersonAddressStreetKey: @"1234 Laurel Street", (NSString *) kABPersonAddressCityKey: @"Atlanta", (NSString *) kABPersonAddressStateKey: @"GA", (NSString *) kABPersonAddressZIPKey: @"30303" }; ABMultiValueAddValueAndLabel(shippingAddress, (__bridge CFDictionaryRef) addressDictionary, kABOtherLabel, nil); success = ABRecordSetValue(record, kABPersonAddressProperty, shippingAddress, &error); if (!success) { /* ... handle error ... */ } request.shippingAddress = record; CFRelease(shippingAddress); CFRelease(record);
存储额外信息
使用applicationData属性来存储一些在你的应用中关于这次支付请求的唯一标识信息,比如一个购物车的标识符。在用户授权支付之后,这个属性的哈希值会出现在这次支付的token中。
part 4 授权支付
支付授权过程是由支付授权view controller和它的代理协作完成的。支付授权view controller做了两件事情:它让用户选择支付请求所必需的账单和配送信息,还有让用户最终授权同意这次支付。当用户和view controller交互时,代理方法就会被调用,这样你的应用就可以不断地更新显示的信息--例如在配送地址更改后更新配送费用。用户最终授权支付请求之后代理方法同样也会被调用。
注意:在实现这些方法时注意,这些方法可能会被多次调用,而它们被调用的顺序取决于用户的行为的顺序。
在所有这个授权过程中被调用的代理方法中,都会有一个completion block被做为参数之一传入,支付授权view controller会在一个代理方法执行完毕(通过调用completion块)后再调用另一个代理方法。唯一的例外是paymentAuthorizationViewControllerDidFinish:方法:它不包含completion block,所以它可以在任何时候被调用。
这个completion block有一个传入参数,基于现有的可用信息,你可以通过这个参数并指定这次交易的状态。如果这次交易没有任何问题,传入PKPaymentAuthorizationStatusSuccess,否则,你要传入一个识别问题的值。
通过在PKPaymentAuthorizationViewController类的构造方法中传入一个支付请求来对它进行实例化,然后给这个视图控制器设置一个代理,就可以把它展示给用户了。
PKPaymentAuthorizationViewController *viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request]; if (!viewController) { /* ... Handle error ... */ } viewController.delegate = self; [self presentViewController:viewController animated:YES completion:nil];
当用户与这个视图控制器进行交互时,它的代理方法会被调用。
通过代理更新配送方式和费用
当用户提供配送信息之后,授权view controller 会调用paymentAuthorizationViewController:didSelectShippingAddress:completion: 和paymentAuthorizationViewController:didSelectShippingMethod:completion:这两个代理方法。在这两个方法中根据最新信息来更新支付请求。
- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controllerdidSelectShippingAddress:(ABRecordRef)addresscompletion:(void (^)(PKPaymentAuthorizationStatus, NSArray *, NSArray *))completion {self.selectedShippingAddress = address;[self updateShippingCost];NSArray *shippingMethods = [self shippingMethodsForAddress:address];completion(PKPaymentAuthorizationStatusSuccess, shippingMethods, self.summaryItems); }- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controllerdidSelectShippingMethod:(PKShippingMethod *)shippingMethodcompletion:(void (^)(PKPaymentAuthorizationStatus, NSArray *))completion {self.selectedShippingMethod = shippingMethod;[self updateShippingCost];completion(PKPaymentAuthorizationStatusSuccess, self.summaryItems); }
当支付被授权后,支付token会被创建
当用户最终授权了一个支付请求,框架会通过与苹果服务器和嵌入在设备中的一个安全模块进行通信,生成一个支付token。然后你在paymentAuthorizationViewController:didAuthorizePayment:completion:方法中将这个token和其它一些你需要用来处理这次购买的信息--例如配送地址和购物车标识--发送给你的服务器。这个过程是这样的:
框架发送支付请求给安全模块,只有安全模块可以访问存储在设备上的标记化的卡信息。
安全模块把特定的卡和商家等支付数据加密,以保证只有苹果可以读取,然后发送给框架。框架会将这些数据发送给苹果。
苹果服务器再次加密这些支付数据,以保证只有商家可以读取。然后服务器对它进行签名,生成支付token,然后发送给设备。
框架调用相应的代理方法并传入这个token,然后你的代理方法传送token给你的服务器。
至于你的服务器采取的行为要取决于你是自己处理这次支付或者你是和其它支付平台合作来进行支付处理。不管怎样,你的服务器处理这个订单然后传送一个状态信息给设备,代理方法会把这个状态信息传送给completion块,像在“Processing a Payment”中讨论过的。
- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion { NSError *error; ABMultiValueRef addressMultiValue = ABRecordCopyValue(payment.billingAddress, kABPersonAddressProperty); NSDictionary *addressDictionary = (__bridge_transfer NSDictionary *) ABMultiValueCopyValueAtIndex(addressMultiValue, 0); NSData *json = [NSJSONSerialization dataWithJSONObject:addressDictionary options:NSJSONWritingPrettyPrinted error: &error]; // ... Send payment token, shipping and billing address, and order information to your server ... PKPaymentAuthorizationStatus status; // From your server completion(status); }
在代理方法中释放授权View Controller
在框架显示交易状态之后,授权View Controller会调用代理paymentAuthorizationViewControllerDidFinish:的方法。在这个方法的实现中,先释放授权页面控制器再显示你自己的订单确认页面。
- (void) paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller { [controller dismissViewControllerAnimated:YES completion:nil]; }
Part 5 支付处理
处理一个支付请求涉及以下几个步骤:
把支付信息,以及支付流程+所需的其他信息,一起发送给你的服务器。
验证支付数据的哈希表和签名
为加密过的支付数据解码
向支付处理系统提交支付数据
向订单追踪系统提交订单
处理支付请求时,你有两个选择;你既可以利用支付平台处理支付请求,也可以自己实现支付请求处理流程。一个常用的支付平台可以完成上述大部分操作。
读取,验证,以及处理支付信息需要有一定的相关密码知识,例如计算SHA-1哈希表,读取和验证PKCS#7签名,执行Elliptic Curve Diffie-Hellman密匙交换。如果没有一定的密码学背景,你可以考虑使用第三方支付平台来完成这些操作。
关于支持Apple Pay支付平台的更多信息,请参考developer.apple.com/apple-pay/
处理支付请求所用的信息拥有一种嵌套式的数据结构,如下图。支付令牌是PKPaymentToken类的实例。其paymentData属性值是一个JSON词典,它的头文件信息可以用来验证和加密支付数据。加密过的数据信息包括支付金额、持卡人姓名,以及一些其他指定的支付处理协议。
关于支付数据结构格式的详细信息,请参看:Payment Token Format Reference.
Figure 5-1支付数据结构
apple pay代码实现相关推荐
- iOS App集成Apple Pay教程(附示例代码)
苹果在本周一发布了iOS 8.1版本,并正式开放了Apple Pay支付系统.Apple Pay是一个基于NFC的支付系统,不久将被数以万计的线下零售商店予以支持.即便这项科技并不是彻底的突破性进展, ...
- Apple Pay及其背后的安全技术
2019独角兽企业重金招聘Python工程师标准>>> 1. 什么是Apple Pay Apple Pay是Apple公司创新的一种安全支付方式.利用Apple Pay,用户可以在 ...
- ios apple pay 证书配置
一 环境配置 需要开发者账号 开发者中心https://developer.apple.com/membercenter/index.action 添加一个APP IDs 二.配置Merchant I ...
- apple pay 技术_如何在Apple Watch上设置和使用Apple Pay
apple pay 技术 Thanks to the proliferation of Apple Pay compatible terminals popping up at retailers a ...
- iOS Apple Pay开发流程
一:介绍 项目中要用到支付功能,需要支付宝支付.支付宝网页支付.微信支付.银联支付.Apple pay,所以打算总结一下,方便以后的查阅,也方便大家, 用到的地方避免再次被坑. 今天我们就主要介绍一下 ...
- iOS Apple Pay(银联渠道) 、云闪付
首先提一下.Apple pay 和 云闪付是两个东西.刚开始的时候产品理解不清楚,他们就认为是一个东西 Apple Pay:用的是苹果的设备,内部的资金的流向都是第三方操作的,我这边用的是银联渠道.你 ...
- 接入Apple Pay流程
接入Apple Pay流程 最近在做IOS内购的后端事项,所以总结下整个流程,都是参考网上大佬的. 首先我们要搞清楚两个概念:苹果支付(Apple Pay)和IOS内购(IAP) 苹果支付:是一种支付 ...
- apple pay 技术_如何在手机上设置Apple Pay和Google电子钱包
apple pay 技术 In case you hadn't noticed recently, paying for stuff with your phone is becoming a pre ...
- apple pay
本文由CocoaChina译者xiaoying.tr培子翻译自苹果官方文档:Apple Pay Programming Guide 目录 关于Apple Pay 配置支付环境 创建支付请求 授权支付 ...
- 最全的apple pay苹果支付步奏
2016年2月18日上午,苹果公司宣布,与中国银联达成合作,正式在中国大陆上线Apple Pay服务. Apple Pay 是一个基于 NFC 的支付系统,几乎所有的银行都支持.不知道大家还有没有印象 ...
最新文章
- 成为优秀UI设计师需要具备哪些条件?
- Lucene教程具体解释
- python数据分析及展示(一)
- 莱特准则 matlab,初学MATLAB,遇到一简单的题目,一点头绪也没有啊.99
- 【Windows10下OpenCV 3.4.0 + Visual Studio 2015开发环境的配】
- 为了使界面组件更圆滑,Swing,且跨系统
- 9行代码AC——HDU 6857 -Clockwise or Counterclockwise(2020 Multi-University Training Contest 8)(判断三点顺序)
- lstm数学推导_如何在训练LSTM的同时训练词向量?
- opencv简单的矩阵操作
- esp8266手机端网络调试助手_esp8266定时控制
- TNonblockingServer 连接管理
- vivo X Fold或首发国产最强屏幕:120Hz LTPO 3.0
- 博客园markdown公式
- 分析技术在PMP中的应用
- C和C++的关系, namespace, struct , class
- Mac配置vscode ssh远程连接主机(远程办公必备)
- TeamTalk部署详细教程(最全最新TeamTalk部署教程助你一次部署成功)
- 一台计算机安装几个操作系统,电脑装3个系统-一台电脑可以安装几个操作系统?...
- Flutter 使用阿里巴巴icon库
- 上网课的心得体会1000字_上网课的感受作文600字
热门文章
- python :tushare 唐奇安通道
- 完整方法:摄像头打不开,驱动无法安装成功,设备状态显示由于其配置信息(注册表中的)不完整或已损坏,windows无法启动这个硬件设备。(代码19)
- QT Libvlc音视频环境配置及编译错误解决
- OSChina 周二乱弹 —— 程序员如何转行卖烧烤
- 计算机电源触,笔记本电源接触不良会怎样【图文教程】
- simulink中对powergui的使用
- C#用NPOI控件把MySQL数据库中查询符合条件的数据导出到EXCEL
- uva10246最短路 + 枚举 + 数组记忆
- linux find命令按文件内容查找,linux下的find文件查找命令与grep文件内容查找命令...
- 向量积计算三角形面积