码迷,mamicode.com
首页 > 移动开发 > 详细

iOS开发笔记(5)---- 应用内接入Apple Pay

时间:2015-08-05 01:07:46      阅读:453      评论:0      收藏:0      [点我收藏+]

标签:ios开发   apple-pay   pkpayment   passkit   应用内支付   

自2014年苹果秋季发布会至今,Apple Pay推出已将近一年时间,我们对其便利性与安全性也早有耳闻,然而时至今日其使用范围仍然只限美国、英国两地区,对于在中国区的引入,我们只能报以期望。

总体来说,在应用内集成Apple Pay需要两个部分:交易授权与交易处理。交易授权在应用内进行,通过PassKit.framework所提供的接口向用户获取支付授权;而交易处理则需要授权后调用可受理交易的服务器接口,你可以选择某个支付平台来处理交易,或者也可以自己实现交易处理过程,苹果官方比较推荐前者。
技术分享

准备工作:

在接入Apple Pay之前,首先要申请MerchantID及对应证书。

  1. 申请 MerchantID
    登陆MemberCenter,选择Certificates, Identifiers & Profiles;
    在Identifiers下选择Merchant IDs,点击右上角添加按钮添加Merchant ID;
    输入描述信息和标识符(格式为merchant.com.company.productid),继续至完成即可。
    技术分享
  2. 本地生成CSR文件,用于请求证书。
    打开钥匙串访问工具,在钥匙串访问下拉菜单选中证书助理-》从证书颁发机构请求证书;
    输入appId邮件地址、名称,选择存储到磁盘,勾选让我指定秘钥对信息;
    秘钥大小选择256位,算法选择ECC。
    技术分享
  3. 请求证书
    进入MemberCenter,根据之前步骤找到前面申请的Merchant ID;
    在这里可以编辑该项,上传之前生成的CSR文件并生成cer证书文件;
    下载证书文件即可。
    技术分享

工程设置

在应用内集成Apple Pay,还需要引用依赖库PassKit.framework,并且在Capability中启用Apple Pay权限(在这里需要配置merchantId)。
技术分享

到这里我们的准备工作就完成了,接下来开始集成Apple Pay。

创建支付请求

在真正创建支付请求之前,我们应该先对当前的支付环境进行检测,看看当前设备、系统及Apple Pay设置是否满足支付条件。

//检查当前设备是否可以支付
[PKPaymentAuthorizationViewController canMakePayments]

//检查用户是否可进行某种卡的支付,目前仅支持Amex、MasterCard与Visa三种卡
[PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks: @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard,PKPaymentNetworkVisa]]

在环境检测完成后即可创建支付请求。

  • 设置币种、国家码及merchant标识符等基本信息
PKPaymentRequest *request=[PKPaymentRequest new];
request.currencyCode = @"USD";
request.countryCode = @"US";
request.merchantIdentifier = @"merchant.com.example";
  • 设置费用项
    在这里可以设置费用的各组成部分及最后结算,包括小计、运费、折扣等项,每一项包含标签字符串和金额两个属性。
//小计
NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO];
self.subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"Subtotal" amount:subtotalAmount];

//折扣
NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithMantissa:200 exponent:-2 isNegative:YES];
self.discount = [PKPaymentSummaryItem summaryItemWithLabel:@"Discount" amount:discountAmount];

// 合计
NSDecimalNumber *totalAmount = [NSDecimalNumber zero];
totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount];
totalAmount = [totalAmount decimalNumberByAdding:discountAmount];
self.total = [PKPaymentSummaryItem summaryItemWithLabel:@"My Company Name" amount:totalAmount];


 //支付请求的支付总结属性是一个数组,数组中的最后一个PKPaymentSummaryItem为合计。
self.summaryItems = @[self.subtotal, self.discount, self.total];
request.paymentSummaryItems = self.summaryItems;
  • 设置交易处理参数
//设置支持卡种
request.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa];


// 设置支持的交易处理协议,3DS必须支持,EMV为可选
request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV;
  • 设置邮寄地址和账单地址
 request.requiredBillingAddressFields = PKAddressFieldEmail;
    request.requiredShippingAddressFields=PKAddressFieldPostalAddress;

    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);
  • 设置邮寄方式

    NSDecimalNumber *freeAmount = [NSDecimalNumber decimalNumberWithString:@"0.00"];
    PKShippingMethod *freeShipping = [PKShippingMethod summaryItemWithLabel:@"Free Shipping" amount:freeAmount];
    freeShipping.detail = @"Arrives by July 2";
    freeShipping.identifier = @"free";

    NSDecimalNumber *standardAmount = [NSDecimalNumber decimalNumberWithString:@"3.21"];
    PKShippingMethod *standardShipping = [PKShippingMethod summaryItemWithLabel:@"Standard Shipping" amount:standardAmount];
    standardShipping.detail = @"Arrives by June 29";
    standardShipping.identifier = @"standard";

    NSDecimalNumber *expressAmount = [NSDecimalNumber decimalNumberWithString:@"24.63"];
    PKShippingMethod *expressShipping = [PKShippingMethod summaryItemWithLabel:@"Express Shipping" amount:expressAmount];
    expressShipping.detail = @"Ships within 24 hours";
    expressShipping.identifier = @"express";

    request.shippingMethods== @[freeShipping, standardShipping, expressShipping];

到这里,一个支付请求已经创建完成,接下来我们需要用它来创建一个PKPaymentAuthorizationViewController,并通过实现PKPaymentAuthorizationViewController的委托方法来获取授权。

PKPaymentAuthorizationViewController *viewController =
    [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
    if (!viewController) { /* ... Handle error ... */ }
    viewController.delegate = self;
    [self presentViewController:viewController animated:YES completion:nil];

实现支付授权委托

实现支付授权的委托,也就是实现PKPaymentAuthorizationViewControllerDelegate协议,这里面有两个必选方法:

//完成授权后的回调方法,这里可以调用server的交易处理接口,并在处理完成后通过completion块通知PKPaymentAuthorizationViewController交易状态
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                       didAuthorizePayment:(PKPayment *)payment
                                completion:(void (^)(PKPaymentAuthorizationStatus status))completion;


//交易完成后回调方法,这里就可以关掉PKPaymentAuthorizationViewController了
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller;

除此之外,还有三个可选方法:

//选择邮寄地址之后回调,这里可以根据所选地址更改邮寄方式及费用,并通过completion块更新PKPaymentAuthorizationViewController
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                  didSelectShippingAddress:(ABRecordRef)address
                                completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray *shippingMethods, NSArray *summaryItems))completion;

//选择邮寄方式后回调,这里可以根据所选邮寄方式更新费用信息,并通过completion块更新PKPaymentAuthorizationViewController
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                   didSelectShippingMethod:(PKShippingMethod *)shippingMethod
                                completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray *summaryItems))completion;

//输完指纹或密码之后,授权支付之前回调
-(void)paymentAuthorizationViewControllerWillAuthorizePayment:(PKPaymentAuthorizationViewController *)controller NS_AVAILABLE_IOS(8_3);

以下为委托方法的部分实现:


-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectShippingAddress:(ABRecordRef)address completion:(void (^)(PKPaymentAuthorizationStatus, NSArray *, NSArray *))completion{
    [self updateShippingMethods];
    completion(PKPaymentAuthorizationStatusSuccess,self.shippingMethods,self.summaryItems);
}

-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectShippingMethod:(PKShippingMethod *)shippingMethod completion:(void (^)(PKPaymentAuthorizationStatus, NSArray *))completion{

    [self updateSummaryItems:shippingMethod.identifier];
    completion(PKPaymentAuthorizationStatusSuccess,self.summaryItems);

}

-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion{
    //在这里调用服务器处理交易,并获取交易状态
    completion(PKPaymentAuthorizationStatusSuccess);
}

-(void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller{
    [controller dismissViewControllerAnimated:true completion:nil];
}


-(void) updateShippingMethods{
    NSDecimalNumber *freeAmount = [NSDecimalNumber decimalNumberWithString:@"0.00"];
    PKShippingMethod *freeShipping = [PKShippingMethod summaryItemWithLabel:@"Free Shipping" amount:freeAmount];
    freeShipping.detail = @"Arrives by July 2";
    freeShipping.identifier = @"free";

    NSDecimalNumber *standardAmount = [NSDecimalNumber decimalNumberWithString:@"3.21"];
    PKShippingMethod *standardShipping = [PKShippingMethod summaryItemWithLabel:@"Standard Shipping" amount:standardAmount];
    standardShipping.detail = @"Arrives by June 29";
    standardShipping.identifier = @"standard";

    NSDecimalNumber *expressAmount = [NSDecimalNumber decimalNumberWithString:@"24.63"];
    PKShippingMethod *expressShipping = [PKShippingMethod summaryItemWithLabel:@"Express Shipping" amount:expressAmount];
    expressShipping.detail = @"Ships within 24 hours";
    expressShipping.identifier = @"express";

    _shippingMethods= @[freeShipping, standardShipping, expressShipping];
}

-(void) updateSummaryItems:(NSString *)identifier{
    if ([identifier isEqualToString:@""]) {
        return;
    }

    NSDecimalNumber *shippingAmount;
    if ([identifier isEqualToString:@"standard"]) {
        shippingAmount=[NSDecimalNumber decimalNumberWithMantissa:321
                                                         exponent:-2 isNegative:NO];
    }else if ([identifier isEqualToString:@"Express"]) {
        shippingAmount=[NSDecimalNumber decimalNumberWithMantissa:2463
                                                         exponent:-2 isNegative:NO];
    }

    PKPaymentSummaryItem* shipping=[PKPaymentSummaryItem summaryItemWithLabel:@"Shipping"
                                                 amount:shippingAmount];


    NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275
                                                                        exponent:-2 isNegative:NO];
    PKPaymentSummaryItem* subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"Subtotal"
                                                                         amount:subtotalAmount];

    NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithMantissa:200
                                                                        exponent:-2 isNegative:YES];
    PKPaymentSummaryItem* discount = [PKPaymentSummaryItem summaryItemWithLabel:@"Discount"
                                                                         amount:discountAmount];

    NSDecimalNumber *totalAmount = [NSDecimalNumber zero];
    totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount];
    totalAmount = [totalAmount decimalNumberByAdding:discountAmount];
    totalAmount = [totalAmount decimalNumberByAdding:shippingAmount];
    PKPaymentSummaryItem* total = [PKPaymentSummaryItem summaryItemWithLabel:@"Ipaynow"
                                                                      amount:totalAmount];

    _summaryItems=@[subtotal, shipping, discount, total];

}

以上,就是在应用内接入Apple Pay的主要内容。

版权声明:本文为博主原创文章,未经博主允许不得转载。

iOS开发笔记(5)---- 应用内接入Apple Pay

标签:ios开发   apple-pay   pkpayment   passkit   应用内支付   

原文地址:http://blog.csdn.net/l964968324/article/details/47283357

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!