apple pay代码实现

一、代码实现之前先配置证书和Merchant ID :

具体操作看:http://blog.csdn.net/songchunmin_/article/details/51543356

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 *)controller
                       didAuthorizePayment:(PKPayment *)payment
                                completion:(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 passed
    BOOL 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 status

        NSLog(@"Payment was successful");

        //        [Crittercism endTransaction:@"checkout"];

    } else {
        completion(PKPaymentAuthorizationStatusFailure);

        // do something to let the user know the status

        NSLog(@"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 *)controller
                   didSelectShippingAddress:(ABRecordRef)address
                                 completion:(void (^)(PKPaymentAuthorizationStatus, NSArray *, NSArray *))completion
{
    self.selectedShippingAddress = address;
    [self updateShippingCost];
    NSArray *shippingMethods = [self shippingMethodsForAddress:address];
    completion(PKPaymentAuthorizationStatusSuccess, shippingMethods, self.summaryItems);
}
 
- (void) paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                    didSelectShippingMethod:(PKShippingMethod *)shippingMethod
                                 completion:(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 支付处理

处理一个支付请求涉及以下几个步骤:

  1. 把支付信息,以及支付流程+所需的其他信息,一起发送给你的服务器。
  2. 验证支付数据的哈希表和签名
  3. 为加密过的支付数据解码
  4. 向支付处理系统提交支付数据
  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支付数据结构

时间: 2024-11-09 16:15:41

apple pay代码实现的相关文章

iOS App集成Apple Pay教程(附示例代码)

苹果在本周一发布了iOS 8.1版本,并正式开放了Apple Pay支付系统.Apple Pay是一个基于NFC的支付系统,不久将被数以万计的线下零售商店予以支持.即便这项科技并不是彻底的突破性进展,但它足以推动许多公司和零售商来支持这种支付方式,并成为苹果又一项成功的投资. Apple Pay还给开发者带来了处理支付的新渠道,用户将期望在应用中使用它,因为它将验证和交易极端简化,仅需手指轻轻一触即可完成,如果应用里面有涉及到交易,开发者很有必要集成Apple Pay.那么如何将Apple Pa

ios apple pay 证书配置

一 环境配置 需要开发者账号 开发者中心https://developer.apple.com/membercenter/index.action 添加一个APP IDs 二.配置Merchant IDs商业ID   下面进行appids和商业id的绑定 之后在回到appids中查看id中的apple pay,发现已经变为可使用状态了 接下来是为商业id生成证书. 点击Merchant IDs 点击id.点击编辑. 这里会有一个提示信息.提示是否允许在美国以外的地区使用apple pay?当然要

Apple Pay(转)

Apple Pay 是在 iOS 8 中第一次被介绍,它可以为你的应用中的实体商品和服务,提供简单.安全.私密的支付方式.它使得用户支付起来非常简便,只需按一下指纹就可以授权进行交易. Apple Pay 只能在特定的设备上使用,目前为止,这些设备包括 iPhone 6, iPhone 6+, iPad Air 2, iPad mini 3. 这是因为 Apple Pay 需要特定的硬件芯片来支持,这个硬件叫做 Secure Element (简称SE,安全元件),他可以用来存储和加解密信息.

Apple Pay

Apple Pay运行环境:iPhone6以上设备,操作系统最低iOS9.0以上,部分信息设置需要iOS9.2以上.目前还不支持企业证书添加. 环境搭建好后可以在模拟器上面运行,xcode7.2.1+iPhone6SP9.2系统下,系统会绑定几种虚拟的银行卡,和几个联系人,方便调试,支付也不会发生真实的付款,真的很方便. 准备工作 在接入Apple Pay之前,首先要申请MerchantID及对应证书.(申请MerchantID及对应证书详细图文教程) 工程设置 bundleID设置 Capab

Swift # Apple Pay集成

苹果正式开放了Apple Pay支付系统.Apple Pay是一个基于NFC的支付系统,不久将被数以万计的线下零售商店予以支持.即便这项科技并不是彻底的突破性进展,但它足以推动许多公司和零售商来支持这种支付方式,并成为苹果的又一项成功的投资. Apple Pay还给开发者带来了处理支付的新渠道,用户将期望在应用中使用它,因为它将验证和交易极端简化,仅需手指轻轻一触即可完成,如果应用里面有涉及到交易,开发者很有必要集成Apple Pay.那么如何将Apple Pay功能集成到你的应用里呢? 在Ap

App Store审核指南中文版(2014.9.10更新):新增Apple Pay相关内容

苹果在9月3日对App Store审核指南进行了重大更新,新添加了扩展.HealthKit.HomeKit以及TestFlight相关内容.另外,在9月10日新品发布会之后,苹果再次更新了App Store审核指南,添加Apple Pay相关内容.文中红色部分是相对于此前版本的新增内容,蓝色部分表示苹果相关官方文档的链接. App Store Review Guidelines(英文版). 前言 感谢您付出宝贵的才华与时间来开发iOS应用程程序.从职业与报酬的角度而言,这对于成千上万的开发员来说

开发apple pay碰到的问题总结

本来想简单总结一下Apple Pay 开发过程中的几个问题, 结果被下面这篇文章全碰上了, 干脆全文转载, 作者对相关资源整理得比较详细, 比较有参考价值 总的来说, 我们做过 APNs 推送的话, 申请 商户ID 并关联到 apple id, 申请证书, 生成provisioning profile等步骤都差不多 然后我真机调试有两个地方没通过, 下文也总结了, 我拎出来单独说一下: 1, Payment request is invalid: check your entitlements.

Apple Pay编程指导

1.About Apple PayApple Pay是一种移动支付技术,让使用者把它们对真实的物品和服务的支付信息以一种方便和安全的方式给你. 对于在app中给出的数字物品和服务,可查看In-App Purchase Programming Guide. Working with Apple Pay使用Apple Pay功能的Apps需要在Xcode 中开启Apple Pay capabilities.也需要注册一个商家标识并设置密钥(用来加密发送支付数据给服务器). 初始化支付时,app创建一

iOS开发 Apple Pay

一.什么是Apple Pay? 1. 概念 Apple Pay,简单来说, 就是一种移动支付方式.通过Touch ID/ Passcode,用户可使用存储在iPhone 6, 6p等设备上的信用卡和借记卡支付证书来授权支付: 它是苹果公司在2014苹果秋季新品发布会上发布的一种基于NFC的手机支付功能,于2014年10月20日在美国正式上线,2016年2月18日凌晨5:00, Apple Pay 业务在中国上线. 2. 使用前提 (1). 支持设备 Apple Pay支持的硬件设备 (表1) 线