当前位置: 首页>后端>正文

apple pay(苹果支付)简单使用

官网 apple pay 配置(https://developer.apple.com/cn/help/account/configure-app-capabilities/configure-apple-pay)

一、创建 merchantID

1、登录开发者账号(https://developer.apple.com/account/resources/identifiers),创建 merchantID

apple pay(苹果支付)简单使用,第1张
创建 merchantID 1
apple pay(苹果支付)简单使用,第2张
创建 merchantID 2
apple pay(苹果支付)简单使用,第3张
创建 merchantID 3
apple pay(苹果支付)简单使用,第4张
创建 merchantID 4
apple pay(苹果支付)简单使用,第5张
创建 merchantID 5

经过上面的 5 个步骤创建merchantID成功,下面就是进行merchantID的配置

apple pay(苹果支付)简单使用,第6张
配置 merchantID 1
点击第一个上传文件,上传的文件是付款处理证书。

官网创建付款处理证书(https://developer.apple.com/cn/help/account/configure-app-capabilities/configure-apple-pay#create-a-payment-processing-certificate)

apple pay(苹果支付)简单使用,第7张
配置 merchantID 2
apple pay(苹果支付)简单使用,第8张
配置 merchantID 3
点击第二个上传文件(on the web),上传的文件是付款处理证书。

官网创建付款处理证书(https://developer.apple.com/cn/help/account/configure-app-capabilities/configure-apple-pay#create-a-payment-processing-certificate)

apple pay(苹果支付)简单使用,第8张
配置 merchantID 4

上传证书成功示例

apple pay(苹果支付)简单使用,第10张
配置 merchantID 成功示例

二、关联 merchantID

1、登录开发者账号(https://developer.apple.com/account/resources/identifiers),选择自己的项目 ID

apple pay(苹果支付)简单使用,第11张
选择自己的项目 ID

2、选择 apple pay 权限

apple pay(苹果支付)简单使用,第12张
选择 apple pay 权限
apple pay(苹果支付)简单使用,第13张
项目关联merchantID

3、关联成功示例

apple pay(苹果支付)简单使用,第14张
项目关联merchantID示例

三、项目配置

1、项目xcode代码配置

apple pay(苹果支付)简单使用,第15张
项目xcode代码配置
<key>com.apple.developer.in-app-payments</key>
    <array>
        <string>merchant.******</string>
    </array>

四、项目核心代码

1、设置支付请求包含的地区和货币信息

static NSString * _Nonnull const kApplepay_merchantID = @"merchant.******"; //这是之前你设置好的Merchant ID
static NSString * _Nonnull const kApplepay_currencyCode = @"CNY"; //人民币是CNY
static NSString * _Nonnull const kApplepay_countryCode = @"CN"; //中国是CN

2、判断是否可以支付

在创建支付请求之前,通过调用PKPaymentAuthorizationViewController类的canMakePaymentsUsingNetworks:方法,确定用户是否能够使用您支持的网络进行支付。要检查Apple Pay是否受到该设备硬件和家长控制的支持,可以使用canMakePayments方法。

注意:PKPaymentAuthorizationController类执行与PKPaymentAuthorizationViewController类相同的角色,但它不依赖于UIKit框架。这意味着授权控制器可以用于视图控制器不能使用的地方(例如,在watchOS应用程序或intent扩展中)。

如果canMakePayments返回NO,则该设备不支持Apple Pay。不要显示Apple Pay按钮。回到另一种支付方式。

如果canMakePayments返回YES,而canMakePaymentsUsingNetworks:返回NO,说明设备支持Apple Pay,但是用户没有为任何请求的网络添加卡。您可以选择显示一个支付设置按钮,提示用户设置他的卡。只要用户点击此按钮,就开始设置新卡的过程(例如,通过调用openPaymentSetup方法,会跳转到wallet)。

只要用户按下Apple Pay按钮,就必须开始支付授权过程。在提交付款请求之前,不能要求用户执行任何其他任务。例如,如果用户需要输入折扣代码,您必须在他按下Apple Pay按钮之前输入。(意思是只要按下Apple Pay按钮,就只能执行付款流程,其他需要用户操作的事情放在之前去做)

3、支付请求包含的支付清单

PKPaymentSummaryItem类表示的付款摘要项向用户描述付款请求的不同部分。使用少量的汇总项目——通常是小计、折扣、运费、税金和总金额。如果您没有任何额外的费用(例如,运费或税),只需使用购买的总额。在应用程序的其他地方提供逐项成本的详细信息。

每个摘要项都有一个标签和一个金额,如清单3-1所示。标签是用户可读的项目摘要描述。金额为相应的支付金额。付款请求中的所有金额都使用付款请求中指定的货币。对于折扣或优惠券,将金额设置为负数。

清单3-1:创建支付清单

// 89.99 subtotal
NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:8999 exponent:-2 isNegative:NO];
self.subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"Subtotal" amount:subtotalAmount];

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

注意:付款汇总项使用NSDecimalNumber类将金额存储为基数为10的数量。这个类的实例可以通过显式地指定尾数和指数(如代码清单所示)来创建,也可以通过提供数量作为字符串并指定区域设置来创建。例如,在财务计算中一定要使用基数为10的数字,以确定5%的折扣金额。
虽然看起来更方便,但是IEEE浮点数据类型(floatDouble)不适合进行财务计算。这些数据类型使用以2为基础的数字表示,这意味着一些十进制数字不能被精确地表示—例如,0.42必须近似为0.41999循环。这种近似可能导致财务计算返回不正确的结果。

(NSDecimalNumber一般用于和钱打交道的数据存储,因为普通的浮点是有误差的,NSDecimalNumber弥补了这个问题)

列表中的最后一个付款汇总项是总金额。通过添加所有其他汇总项的金额来计算总金额。总计与其他汇总项的显示方式不同:使用您的公司名称作为其标签,并使用所有其他汇总项的总额作为其金额。使用paymentSummaryItems属性将付款摘要项添加到付款请求中。

如果您不知道授权支付时的实际成本(例如出租车费用),则使用PKPaymentSummaryItemTypePending类型和0.0金额创建一个小计汇总项目。对于总金额,使用正的非零金额和PKPaymentSummaryItemTypePending类型。然后,系统将成本显示为pending,没有数字数量。

注意:总金额不能是0或者负数。

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;

4、Shipping Method

为每个可用的传送方法创建PKShippingMethod的实例。与其他付款汇总项一样,shipping方法具有用户可读的标签,比如Standard shipping或Next Day shipping,以及表示运费的金额。与其他摘要项不同的是,运输方法还有一个详细的属性,比如“7月29日前到达”或“24小时内到达”,这就解释了运输方法之间的区别。

要区分委托方法中的传递方法,请使用标识符属性。此属性仅供您的应用程序使用—框架将其视为不透明值,并且它不会出现在UI中。在创建每个传送方法时,为其分配唯一标识符。为了便于调试,可以使用简短或缩写的字符串,如“discount”、“standard”或“next-day”。

有些运输方法不是在所有地区都可用,或者对于不同的地址有不同的成本。当用户选择送货地址或方法时,可以更新此信息,如委托更新送货方法和费用中所述。

5、支付处理机制的支持设置

通过使用字符串常量数组填充supportedNetworks属性来指示您支持哪些支付网络。通过为merchantCapabilities性属性设置一个值来指示您支持哪些支付处理协议。你必须支持3DS;只有在支持Apple Pay的情况下才能指定EMV

request.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkDiscover, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa];

// Supports 3DS only
request.merchantCapabilities = PKMerchantCapability3DS;

// Supports both 3DS and EMV (add EMV only if you support Apple Pay in China)
request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV;

6、运输和计费信息设置

填充付款授权视图控制器的requiredBillingAddressFields和requiredShippingAddressFields属性,以指示需要哪些账单和发货信息。当您呈现这个视图控制器时,它会提示用户提供所请求的帐单和发货信息。

request.requiredBillingAddressFields = PKAddressFieldEmail;
request.requiredBillingAddressFields = PKAddressFieldEmail | PKAddressFieldPostalAddress;

注意:只要求填写所需要的信息。请求不必要的信息会给事务增加不必要的复杂性。每一个额外的步骤都增加了用户取消支付的可能性。

如果您有最新的账单和发货联系方式,您可以在付款请求中设置这些信息。Apple Pay默认使用这些信息;但是,用户仍然可以选择其他联系方式作为支付授权过程的一部分。

PKContact *contact = [[PKContact alloc] init];

NSPersonNameComponents *name = [[NSPersonNameComponents alloc] init];
name.givenName = @"Leo";
name.familyName = @"Appleseed";

contact.name = name;

CNMutablePostalAddress *address = [[CNMutablePostalAddress alloc] init];
address.street = @"666888 Street";
address.city = @"ShenZhen";
address.state = @"GA";
address.postalCode = @"000555";

contact.postalAddress = address;

request.shippingContact = contact;

注意:地址信息可以来自iOS中的各种来源。在使用信息之前一定要验证它。

7、设置完整的支付信息示例代码

- (void)configPaymentInformation {
    //开始配置支付信息
    self.payRequest = [[PKPaymentRequest alloc] init];
    self.payRequest.countryCode = @"US";             //国家代码
    self.payRequest.currencyCode = @"USD";           //RMB的币种代码
    self.payRequest.merchantIdentifier = @"merchant.com.aspiraconnect.demo";//申请的merchantID
    
    self.payRequest.supportedNetworks = self.supportedNetworkCards; //用户可以进行支付的银行卡
    
    self.payRequest.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV;
    //设置支持的交易处理协议, 3DS必须支持, EMV为可选
    
    //payRequest.requiredShippingAddressFields = \
    PKAddressFieldPostalAddress | PKAddressFieldPhone | PKAddressFieldName;
    //设置发货地址
    self.payRequest.requiredShippingAddressFields = PKAddressFieldNone;
    //空发货地址
    self.payRequest.shippingMethods = @[];
    NSDecimalNumber *totalAmount = \
    [NSDecimalNumber decimalNumberWithString:@"0.01"];//创建金额
    
    PKPaymentSummaryItem *total = \
    [PKPaymentSummaryItem summaryItemWithLabel:@"My Company Name" amount:totalAmount];
    self.summaryItems = [NSMutableArray arrayWithArray:@[total]];
    self.payRequest.paymentSummaryItems = self.summaryItems;
}

8、支付回调

官网支付回调数据(https://developer.apple.com/documentation/passkit/apple_pay/payment_token_format_reference?language=objc)

 HJApplePayManage *payManage = [HJApplePayManage payWithAmount:totalAmount request:nil isTest:self.isTest presentingVc:self.root authed:^(PKPayment * _Nullable payment, NSString *creditType) {        
            id dic = [NSJSONSerialization JSONObjectWithData:payment.token.paymentData options:NSJSONReadingMutableLeaves error:nil];
// 处理 apple pay 支付回调数据和项目后台数据进行交互
        }];

9、申请黑盒测试 apple ID,添加测试 apply pay 卡数据(https://www.jianshu.com/p/a63756023f53)

实际项目应用代码

.h 文件

#import <PassKit/PassKit.h>

static NSString * _Nonnull const kApplepay_merchantID = @"merchant.******";
static NSString * _Nonnull const kApplepay_currencyCode = @"CNY";
static NSString * _Nonnull const kApplepay_countryCode = @"CN";

typedef void(^shouldVerifyBlock)(PKPayment * __nullable payment, NSString * __nullable creditType);

@interface HJApplePayManage : NSObject

/// 判断苹果支付是否可用
+ (BOOL)canMakePayments;

+ (instancetype)payWithAmount:(NSString *)amount
                      request:(PKPaymentRequest * _Nullable)request
                       isTest:(BOOL)isTest
                 presentingVc:(UIViewController *)presentingVc
                       authed:(shouldVerifyBlock)authBlock;

/// 通知applePayManage接口处理完毕

- (void)serviceVerifyed:(BOOL)verifyed applePayFinished:(dispatch_block_t)applePayFinished;

.m 文件

#import "HJApplePayManage.h"
#import "NSNumber+SPUtilsExtras.h"

API_AVAILABLE(ios(11.0))

@interface HJApplePayManage () <PKPaymentAuthorizationViewControllerDelegate>

@property (nonatomic, copy) void(^authCompletionBlock)(PKPaymentAuthorizationResult *result);

@property (nonatomic, copy) shouldVerifyBlock didAuthorizeBlock;

@property (nonatomic, copy) dispatch_block_t didFinishBlock;

#if Zprd
// 上线环境
#else
// 非 上线环境
@property (nonatomic, assign) BOOL isTest;
#endif

@end

@implementation HJApplePayManage

#pragma mark - Public methods
/*
 判断是否可以支付
 在创建支付请求之前,通过调用PKPaymentAuthorizationViewController类的canMakePaymentsUsingNetworks:方法,确定用户是否能够使用您支持的网络进行支付。要检查Apple Pay是否受到该设备硬件和家长控制的支持,可以使用canMakePayments方法。

 注意:PKPaymentAuthorizationController类执行与PKPaymentAuthorizationViewController类相同的角色,但它不依赖于UIKit框架。这意味着授权控制器可以用于视图控制器不能使用的地方(例如,在watchOS应用程序或intent扩展中)。

 如果canMakePayments返回NO,则该设备不支持Apple Pay。不要显示Apple Pay按钮。回到另一种支付方式。

 如果canMakePayments返回YES,而canMakePaymentsUsingNetworks:返回NO,说明设备支持Apple Pay,但是用户没有为任何请求的网络添加卡。您可以选择显示一个支付设置按钮,提示用户设置他的卡。只要用户点击此按钮,就开始设置新卡的过程(例如,通过调用openPaymentSetup方法,会跳转到wallet)。

 只要用户按下Apple Pay按钮,就必须开始支付授权过程。在提交付款请求之前,不能要求用户执行任何其他任务。例如,如果用户需要输入折扣代码,您必须在他按下Apple Pay按钮之前输入。(意思是只要按下Apple Pay按钮,就只能执行付款流程,其他需要用户操作的事情放在之前去做)
 */
+ (BOOL)canMakePayments {
    
    if(![PKPaymentAuthorizationViewController canMakePayments]){
        NSLog(@"cannot pay");
        return NO;
    }

    if(![PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:@[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa, PKPaymentNetworkChinaUnionPay]]) {
        NSLog(@"Wallet did not add a savings / credit card for this payment network");
        return NO;
    }
    
    NSLog(@"can pay");
    return YES;
}

+ (instancetype)payWithAmount:(NSString *)amount
                      request:(PKPaymentRequest * _Nullable)request
                       isTest:(BOOL)isTest
                 presentingVc:(UIViewController *)presentingVc
                       authed:(shouldVerifyBlock)authBlock
{
    HJApplePayManage *manage = [HJApplePayManage new];
    manage.isTest = isTest;
    [manage applePayWithAmount:amount request:request presentingVc:presentingVc];
    manage.didAuthorizeBlock = authBlock;
    
    return manage;
}

/// 通知applePayManage接口处理完毕

- (void)serviceVerifyed:(BOOL)verifyed applePayFinished:(dispatch_block_t)applePayFinished
{
    self.didFinishBlock = applePayFinished;
    
    PKPaymentAuthorizationResult *authResult;
    if (verifyed) {
        authResult = [[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusSuccess errors:nil];
    } else {
        authResult = [[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusFailure errors:nil];
    }
    
    if (self.authCompletionBlock) self.authCompletionBlock(authResult);
}

#pragma mark - ApplePay PaymentRequest
- (void)applePayWithAmount:(NSString *)amount request:(PKPaymentRequest *)request presentingVc:(UIViewController *)presentingVc
{
    if (!request) {
        request = [[PKPaymentRequest alloc] init];
    }
    
    request.merchantIdentifier = kApplepay_merchantID;
    request.currencyCode = kApplepay_currencyCode;
    request.countryCode = kApplepay_countryCode;
    
    // 支持的支付网络
    //(PKPaymentNetworkChinaUnionPay iOS9.2开始支持)
    if (@available(iOS 12.1.1, *)) {
        request.supportedNetworks = @[PKPaymentNetworkMada, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa, PKPaymentNetworkChinaUnionPay];
    } else {
        request.supportedNetworks = @[PKPaymentNetworkMasterCard, PKPaymentNetworkVisa, PKPaymentNetworkChinaUnionPay];
    }
    
    // 支付请求金额信息列表
    NSDecimalNumber *topupAmount = [NSDecimalNumber decimalNumberWithString:amount];
    
    PKPaymentSummaryItem *topupItem = [PKPaymentSummaryItem summaryItemWithLabel:@"支付总金额" amount:topupAmount];
    
    PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"Demo" amount:topupAmount type:PKPaymentSummaryItemTypeFinal];
    
    request.paymentSummaryItems = @[topupItem, total];
    
    // 3DS支付方式是必须支持的,EMV方式是可选的, PKMerchantCapabilityCredit(信用卡) 充值钱包类项目要注意信用卡不能支持,防止套现违规操作 
#if Zprd
    // 上线环境
    request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV | PKMerchantCapabilityDebit;
#else
    // 非 上线环境
    if (self.isTest) {
        request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV | PKMerchantCapabilityDebit | PKMerchantCapabilityCredit;
    }
    else {
        request.merchantCapabilities = PKMerchantCapability3DS | PKMerchantCapabilityEMV | PKMerchantCapabilityDebit;
    }
#endif
    // 存储额外信息
    //使用applicationData属性来存储一些在你的应用中关于这次支付请求的唯一标识信息,比如一个购物车的标识符。在用户授权支付之后,这个属性的哈希值会出现在这次支付的token中。
    //    request.applicationData = [@"购物车ID: Demo" dataUsingEncoding:NSUTF8StringEncoding];
    

    // 设置 只有指定地区发行的卡才可以进行支付,不是这个地区的卡不能选择支付
// 不设置这个默认全部国家的卡都可以
#if Zprd
    // 上线环境
    NSSet<NSString *> *supportedCountries = [NSSet setWithArray:@[kApplepay_countryCode]];
    request.supportedCountries = supportedCountries;
#else
    // 非 上线环境
    if (self.isTest) {

    }
    else {
        NSSet<NSString *> *supportedCountries = [NSSet setWithArray:@[kApplepay_countryCode]];
        request.supportedCountries = supportedCountries;
    }
#endif
    
    PKPaymentAuthorizationViewController *paymentPane = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
    
    paymentPane.delegate = self;
    paymentPane.definesPresentationContext = YES;
    
    [presentingVc presentViewController:paymentPane animated:YES completion:nil];
}


#pragma mark - ApplePay PKPaymentAuthorizationViewControllerDelegate
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                       didAuthorizePayment:(PKPayment *)payment
                                   handler:(void (^)(PKPaymentAuthorizationResult *result))completion API_AVAILABLE(ios(11.0), watchos(4.0))  {
    
    self.authCompletionBlock = completion;
    
    if (self.didAuthorizeBlock) {
        self.didAuthorizeBlock(payment, payment.token.paymentMethod.network);
    }
    
}

/// 因(PKPaymentNetworkMada iOS12.1.1开始支持) 暂不适配iOS11以下
//- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
//                       didAuthorizePayment:(PKPayment *)payment
//                                completion:(void (^)(PKPaymentAuthorizationStatus status))completion API_DEPRECATED("Use paymentAuthorizationViewController:didAuthorizePayment:handler: instead to provide more granular errors", ios(8.0, 11.0)) {
//
//}

/**
 *  当授权成功之后或者取消授权之后会调用这个代理方法
 */
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller {
    
    [controller dismissViewControllerAnimated:YES completion:^{
        if (self.didFinishBlock) {
            self.didFinishBlock();
        }
    } ];
}


https://www.xamrdz.com/backend/3vm1925275.html

相关文章: