ApplePay 接入教程及开发过程需要注意的点

运行环境##

iphone 6 以及以上,iOS 9.2 以上。目前不支持企业证书添加。
支持模拟器测试。

环境配置##

1、 Xcode 7.2.1 以及以上打开项目,在 Capabilities里将Apple Pay设置为on,如下图,请忽略 Merchant IDmerchant.com.Carman.Paydemo这一项,一会我会详细介绍。

图片-1

这时你会发现 项目 下 会自动 生成一个 类似证书的东西

图片-2

这一步做了什么?
1、自动导入了需要的库文件。
2、添加了一个权限文件(图片-2).

2、 图一我们看到了有个 Merchant ID 选项,而且新建时候是没有配置的,那么需要到哪里去配置呢?
1、访问苹果开发账号,证书中心。
Identifiers -->Merchant IDs
输入描述 和 ID,ID 必须以merchant. 开头

图-3

Continue 到下一步,前方高能警报,嘀嘀嘀~~~~ 坑一出现:报错!!!!!!!

图-4

说明苹果对这个ID 格式是有要求的。多试几次。其实仔细看 图 -3 底下有一行小字,We recommend using a reverse-domain name style string (i.e.,merchant.com.example.merchantname). 最好按照官方要求 merchant.com.example.merchantname 这个格式来。

图 -5

一步一步往下走。
这时候 会提示你 Identifier:merchant.com.Demo.applepaydemo已经生成。

图-6

点击 Done
图 -7

根据上面的提示,点击Edit,接下去应该是需要建证书了。
首次添加时候 会询问你是否 在中国使用。选择 YES(截图是默认状态-NO),一直 continue 。
图-8

3、新建证书
创建 ** Creating a Certificate Signing Request (CSR) CSR 证书,**
Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.
打开钥匙串访问 如下图操作

图-9

生成 CertificateSigningRequest.certSigningRequest(名称可以自定义)
图-10

上传 生成证书


图-11

满怀信心,觉得即将成功是么?

图-12

此证书是由未知颁发机构签名的!!!什么鬼呀,老子的账号明明是正规渠道申请的!
还好有解决方案---点我解决.
点击下载红线项,删除老的证书,重新导入 G2 证书
图-13

以上,ApplePay 所需的环境就算全部配置完成了。
总结一下就一条:生成了 Merchant ID 证书
再看 项目 工程,已经自动生成了 Merchant ID 值,打钩就可以了,如果没有生成,再检查下 项目的 Bundle identifier是否和证书一致。
图-14

代码集成##

首先我们来看下模拟器上Demo 运行的结果:

图-15

这里要说的 重点不在下半部分,而是 Buy with XXPay 这个按钮,我们知道苹果是一个有情(偏)怀(执)的处女座公司,对很多的设计或则交互都有自己的一套规则,ApplePay 的响应 按钮也不例外。不要以为随便 弄个 设计个按钮 就能上线了,这个时候 美工和老板说了都不算,要听苹果的ApplePay 设计规范。不然审核也过不了。

1、
导入头文件,(xcode 7.0 以上已经自动帮我们导入了库,所以我们只需要导入头文件即可)

#import <PassKit/PassKit.h>

2、
PKPaymentAuthorizationViewController Apple pay的展示控件,也是核心类。直接看代码

- (void)actionApplePay:(UIButton *)button {

  if ([PKPaymentAuthorizationViewController canMakePayments]) {

    NSLog(@"Woo! Can make payments!");

    if ([PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:@[
          PKPaymentNetworkChinaUnionPay,
          PKPaymentNetworkMasterCard,
          PKPaymentNetworkVisa
        ]]) {

    } else {
      NSLog(@"用户未添加银行卡");
      return;
    }

    PKPaymentRequest *request = [[PKPaymentRequest alloc] init];

    PKPaymentSummaryItem *widget1 = [PKPaymentSummaryItem
        summaryItemWithLabel:@"Widget 1"
                      amount:[NSDecimalNumber decimalNumberWithString:@"0.01"]];

    PKPaymentSummaryItem *widget2 = [PKPaymentSummaryItem
        summaryItemWithLabel:@"Widget 2"
                      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 = @"CHW";

    //能支付的币种
    request.supportedNetworks = @[
      PKPaymentNetworkChinaUnionPay,
      PKPaymentNetworkMasterCard,
      PKPaymentNetworkVisa
    ];
      
    //Merchant ID
    request.merchantIdentifier = @"merchant.com.Carman.Paydemo";

    // 询问你的付款处理器 (PKMerchantCapabilityCredit
    // 信用卡,PKMerchantCapabilityDebit 借记卡)

    /*
     PKMerchantCapabilityCredit NS_ENUM_AVAILABLE_IOS(9_0)   = 1UL << 2,   //
     支持信用卡
     PKMerchantCapabilityDebit  NS_ENUM_AVAILABLE_IOS(9_0)   = 1UL << 3    //
     支持借记卡
     */
    request.merchantCapabilities = PKMerchantCapabilityCredit;
    // 添加联系人邮箱 及送货地址信息
    //request.requiredShippingAddressFields = PKAddressFieldAll;

    PKPaymentAuthorizationViewController *paymentPane =
        [[PKPaymentAuthorizationViewController alloc]
            initWithPaymentRequest:request];
    paymentPane.delegate = self;
    [self presentViewController:paymentPane animated:TRUE completion:nil];

  } else {
    NSLog(@"设备不支持支付");
  }
}

1、[PKPaymentAuthorizationViewController canMakePayments] 判断设备支持不支持 ApplePay。中国区 是 iphone 6 及以上,iOS9.2
2、canMakePaymentsUsingNetworks: 判断 设备上用户有没有添加银行卡,如果没添加,不写这个判断,真机上会crash。
PKPaymentNetworkChinaUnionPay //中国银联卡
PKPaymentNetworkMasterCard //Master卡
PKPaymentNetworkVisa //Visa卡

3、支付的类目以及总额

PKPaymentRequest *request = [[PKPaymentRequest alloc] init];

    PKPaymentSummaryItem *widget1 = [PKPaymentSummaryItem
        summaryItemWithLabel:@"Widget 1"
                      amount:[NSDecimalNumber decimalNumberWithString:@"0.01"]];

    PKPaymentSummaryItem *widget2 = [PKPaymentSummaryItem
        summaryItemWithLabel:@"Widget 2"
                      amount:[NSDecimalNumber decimalNumberWithString:@"0.01"]];

    PKPaymentSummaryItem *total = [PKPaymentSummaryItem
        summaryItemWithLabel:@"Grand Total"
                      amount:[NSDecimalNumber decimalNumberWithString:@"0.02"]];

    request.paymentSummaryItems = @[ widget1, widget2, total ];

4、countryCode 国家 code ,中国的是 CN ,不太清楚定义的可以查看 countryCode查询网站
5、currencyCode 支付币种 ,人民币 CHW
6、supportedNetworks 能支持的卡种,同 2
7、merchantIdentifier ,终于出现这货了,申请半天的 Merchant ID ,请注意保持一致。
8、
merchantCapabilities
询问你的付款处理器
PKMerchantCapabilityCredit //支持信用卡
PKMerchantCapabilityDebit //支持借记卡
9、requiredShippingAddressFields 添加联系人信息

typedef NS_OPTIONS(NSUInteger, PKAddressField) {
    PKAddressFieldNone                              = 0UL,      // No address fields required.
    PKAddressFieldPostalAddress                     = 1UL << 0, // Full street address including name, street, city, state/province, postal code, country.
    PKAddressFieldPhone                             = 1UL << 1,
    PKAddressFieldEmail                             = 1UL << 2,
    PKAddressFieldName NS_ENUM_AVAILABLE_IOS(8_3)   = 1UL << 3,
    PKAddressFieldAll                               = (PKAddressFieldPostalAddress|PKAddressFieldPhone|PKAddressFieldEmail|PKAddressFieldName)
} NS_ENUM_AVAILABLE(NA, 8_0);

10、调起 ** PKPaymentAuthorizationViewController**

 PKPaymentAuthorizationViewController *paymentPane =
        [[PKPaymentAuthorizationViewController alloc]
            initWithPaymentRequest:request];
    paymentPane.delegate = self;
      
    [self presentViewController:paymentPane animated:TRUE completion:nil];

当然,我们要实现<PKPaymentAuthorizationViewControllerDelegate> 代理

@interface ViewController : UIViewController<PKPaymentAuthorizationViewControllerDelegate>
@end

实现 PKPaymentAuthorizationViewControllerDelegate##

必须实现的两个代理:

#pragma mark-- PKPaymentAuthorizationViewControllerDelegate
- (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;

  if (asyncSuccessful) {
    completion(PKPaymentAuthorizationStatusSuccess);

    NSLog(@"支付成功");

  } else {
    completion(PKPaymentAuthorizationStatusFailure);
    NSLog(@"支付失败");
  }
}

- (void)paymentAuthorizationViewControllerDidFinish:
        (PKPaymentAuthorizationViewController *)controller {
  // hide the payment window
  [controller dismissViewControllerAnimated:TRUE completion:nil];
}

1、paymentAuthorizationViewController:didAuthorizePayment:
completion

支付 状态回调在这里处理,支付成功和失败,订单的地址 以及和 服务器传输数据-token。
2、paymentAuthorizationViewControllerDidFinish:支付结束,关闭 支付弹框。
3、可选的另外的代理 回调 请参考Apple Pay接入详细教程 一文

我们主要来看下** PKPayment** 对象

图-16

token 支付成功之后的回执,需要上传给服务器。
billingAddress 用户账单地址
billingContact 用户账单信息
shippingAddress 送货地址
shippingContact 送货信息
shippingMethod 送货方式
以上的 信息 可以根据自己的需求 上传到服务器

 - (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);

}

更深入了解可以参看官方文档

钱去哪了##

目前为止,我们完成了客户端的ApplePay 代码集成,假设回调的信息也成功上传 服务器,服务器也成功对订单进行了处理,那么用户支付的钱去哪了?
1、钱去了商家的 AppStore 账号?
苹果账号的申请一般都是用信用卡支付 ,业务的收入不太可能直接打到信用卡里。
2、商家 AppStore 账号绑定了商家的银行卡?
我们生成 Merchant ID 证书的时候 并没有这一步。

支付供应商##

苹果官方文档 Apple Pay 入门 明确指出:

图-17

就是说,苹果官方强烈建议开发者接入他合作的支付供应商SDK 来支持ApplePay,这样就能理解了,开发者到支付供应商网站注册相关信息,绑定商户ID ,银行卡等,这样用户的钱就到了商户在支付供应商注册的账号里面。我们可以把支付供应商 理解成付款处理结构。 坑爹呀,上面的集成都白写了!!!

苹果官方在中国合作的指定付款处理结构有 (参考ApplePay 介绍):

中国银联
连连支付
首信易支付
易宝支付
银联商务

这里选择中国银联的sdk 进行介绍,有兴趣的同学可以自行去研究另外几个供应商的支付SDK。

中国银联##

选择中国银联 接入 有个很大的好处 -- 文档非常的详细。
1、中国银联商户入网新手指南
https://merchant.unionpay.com/join/help/director
2、银联商家服务
https://open.unionpay.com/ajweb/product/detail?id=80
3、银联Apple Pay控件开发包
https://open.unionpay.com/ajweb/help/file/techFile?productId=80

银联Apple Pay控件开发包####

下载 银联的Apple Pay 控件开发包,里面有非常详细的 介绍,如何接入ApplePay。


图-18

银联支付控件 SDK 模式 Apple Pay 支付的实现方式###

图-19

1-2、 商户生成订单,通过商户SERVER端将订单信息发送给银联支付网关;
3-4、银联支付网关记录订单信息,返回用来标识订单的 TN 号,经由商户 SERVER 返回至给商户 APP;
5、 商户 APP 调用银联 SDK,将 TN 号传递给银联 SDK
6、 银联 SDK 向 Apple 公司的 PASSKIT FRAMEWORK 发起支付请求;
7、 接口返回加密的支付 Token 信息;
8-9、银联 SDK 将支付 Token 传递给银联支付网关,完成交易认证;
10-12、银联将支付结果返回给商户 APP,商户 SERVER,商户 APP 负责提示用户交易结果。

集成的测试代码介绍##

1-2步、商户生成订单,通过商户SERVER端将订单信息发送给银联支付网关; 代码如下:

- (void) pmPayAction:(id)sender {
    //使用PM环境
    self.tnMode = @"01";
    NSURL* url = [NSURL URLWithString:@"http://101.231.204.84:8091/sim/getacptn"];
    
    NSMutableURLRequest * urlRequest=[NSMutableURLRequest requestWithURL:url];
    NSURLConnection* urlConn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
    [urlConn start];
    [self showAlertWait];
}

1、 self.tnMode = @"01"; //接入模式,标识商户以何种方式调用支付控件,00生产环境,01测试环境
2、http://101.231.204.84:8091/sim/getacptn //银联提供测试的 URL

3-9 步:代码如下:

#pragma mark - connection

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response
{
    NSHTTPURLResponse* rsp = (NSHTTPURLResponse*)response;
    NSInteger code = [rsp statusCode];
    if (code != 200)
    {
        
        [self showAlertMessage:kErrorNet];
        [connection cancel];
    }
    else
    {
        UPRelease(_responseData);
        _responseData = [[NSMutableData alloc] init];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [_responseData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self hideAlert];
    NSString* tn = [[NSMutableString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
    if (tn != nil && tn.length > 0)
    {
        if([PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:@[PKPaymentNetworkChinaUnionPay]])
        {

            [UPAPayPlugin startPay:tn mode:self.tnMode viewController:self delegate:self andAPMechantID:kAppleMerchantID];
        }

    }
    [tn release];
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [self showAlertMessage:kErrorNet];
}

1、** [UPAPayPlugin startPay:tn mode:self.tnMode viewController:self delegate:self andAPMechantID:kAppleMerchantID];**
1、tn / /订单信息
2、self.tnMode //接入模式,标识商户以何种方式调用支付控件,00生产环境,01测试环境
3、kAppleMerchantID //苹果公司分配的商户号,表示调用Apple Pay所需要的MerchantID;(接入银联支付时候,该 MerchantID 需要商家向银联申请生成)

图 -20

10-12步,银联将支付结果返回给商户 APP,商户 SERVER,商户 APP 负责提示用户交易结果。 回调处理。

#pragma mark -
#pragma mark 响应控件返回的支付结果
#pragma mark -
- (void)UPAPayPluginResult:(UPPayResult *)result
{
    if(result.paymentResultStatus == UPPaymentResultStatusSuccess) {
        NSString *otherInfo = result.otherInfo?result.otherInfo:@"";
        NSString *successInfo = [NSString stringWithFormat:@"支付成功\n%@",otherInfo];
        [self showAlertMessage:successInfo];
    }
    else if(result.paymentResultStatus == UPPaymentResultStatusCancel){

        [self showAlertMessage:@"支付取消"];
    }
    else if (result.paymentResultStatus == UPPaymentResultStatusFailure) {
        
        NSString *errorInfo = [NSString stringWithFormat:@"%@",result.errorDescription];
        [self showAlertMessage:errorInfo];
    }
    else if (result.paymentResultStatus == UPPaymentResultStatusUnknownCancel)  {
        
        //TODO UPPAymentResultStatusUnknowCancel表示发起支付以后用户取消,导致支付状态不确认,需要查询商户后台确认真实的支付结果
        NSString *errorInfo = [NSString stringWithFormat:@"支付过程中用户取消了,请查询后台确认订单"];
        [self showAlertMessage:errorInfo];
        
    }
}

运行效果###

图-21
图-22
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容