Apple Pay接入詳細(xì)教程

Apple Pay運(yùn)行環(huán)境:iPhone6以上設(shè)備,操作系統(tǒng)最低iOS9.0以上,部分信息設(shè)置需要iOS9.2以上。目前還不支持企業(yè)證書添加。
環(huán)境搭建好后可以在模擬器上面運(yùn)行,xcode7.2.1+iPhone6SP9.2系統(tǒng)下,系統(tǒng)會(huì)綁定幾種虛擬的銀行卡,和幾個(gè)聯(lián)系人,方便調(diào)試,支付也不會(huì)發(fā)生真實(shí)的付款,真的很方便。
[TCO]

業(yè)務(wù)方面

首先你要明白,ApplePay和支付寶、微信支付最大的不同點(diǎn):用戶的資金不存放在ApplePay。
支付寶、微信支付把用戶的錢從銀行卡里面拿出來放到阿里騰訊公司,ApplePay沒有,錢還是在銀行卡里面,所以說ApplePay相當(dāng)于只是一個(gè)卡包,幫你存放實(shí)體卡而已。
ApplePay里面的Pay,其實(shí)并不屬于蘋果的業(yè)務(wù),只是蘋果公司和銀行合作產(chǎn)生的一種業(yè)務(wù),如果沒有銀行就沒有ApplePay,和銀行是強(qiáng)關(guān)聯(lián)的,和蘋果公司是弱關(guān)聯(lián)的。

  • 銀行會(huì)喜歡ApplePay而不是喜歡支付寶、微信,為什么?
    互聯(lián)網(wǎng)金融時(shí)代,支付寶、微信等網(wǎng)絡(luò)支付渠道把用戶的資金從銀行卡拿到自己的公司賬戶里面,導(dǎo)致了銀行只看到一條的資金流向是支付寶、微信,但是并不清楚用戶把這些錢干嘛了,是投資了還是買買奶粉了。大數(shù)據(jù)時(shí)代這些信息是很珍貴的,(我知道一個(gè)做安全的專家從來不在網(wǎng)上購(gòu)物,即使網(wǎng)上購(gòu)物已經(jīng)成了我們生活不可缺少的一部分,知道他怎么做嗎,他讓自己的秘書去網(wǎng)上幫自己買想要的東西,然后付現(xiàn)金給秘書,注意是現(xiàn)金,不是轉(zhuǎn)賬,扯遠(yuǎn)了)。通過ApplePay銀行就可以了解到用戶的資金流向了

  • 錢支付成功后去哪了?
    這個(gè)問題主要是因?yàn)槲覀儧]有簽約之前發(fā)生了虛擬交易,客戶端簽約方式是和第三方支付平臺(tái)簽約,實(shí)體店接入ApplePay的方式是升級(jí)POS機(jī),支持NFC的POS機(jī),就是和銀行更新合約。
    ApplePay完全不中轉(zhuǎn)用戶的資金,只是一個(gè)保存信用卡、借記卡信息的錢包,并且省去了用戶簽名的過程。所以你除了支持用戶使用這種支付方式,關(guān)鍵還是要和銀行簽約。
    客戶端方面,蘋果目前建議是和第三方合作接入Applepay,比如銀聯(lián)等等,省去了一家家銀行簽約的過程,由第三方和一家家銀行溝通事項(xiàng),商戶之和第三方溝通。所以簽約部分就是和第三方支付平臺(tái)簽約了,錢會(huì)進(jìn)入和第三方簽約的銀行卡內(nèi)。
    蘋果目前提供以下幾個(gè)第三方平臺(tái)簽約
    中國(guó)銀聯(lián)
    連連支付
    首信易支付
    易寶支付
    銀聯(lián)商務(wù)

一般來說銀聯(lián)這些第三方支付會(huì)把ApplePay的流程代碼寫入到他們的SDK里面,如果說你不想了解Applepay的內(nèi)部怎么實(shí)現(xiàn)的,就沒有必要繼續(xù)閱讀了,你只需要去閱讀第三方SDK的接入文檔就行了。

也就是說你自己寫的接入Applepay代碼基本是沒有意義的

準(zhǔn)備工作

在接入Apple Pay之前,首先要申請(qǐng)MerchantID及對(duì)應(yīng)證書。
請(qǐng)移步我寫的申請(qǐng)MerchantID及對(duì)應(yīng)證書詳細(xì)圖文教程

工程設(shè)置

bundleID設(shè)置


Applepay Setting1.png

Capability中啟用Apple Pay權(quán)限,并選擇merchantID。


Applepay Setting2.png

之后項(xiàng)目會(huì)多一個(gè)Applepay的配置文件ApplePayYasin.entitlements


Applepay Setting3.png

需要引用的庫(kù)

Xcode7.0以上不需要再手動(dòng)添加需要引用的庫(kù)了,只需要導(dǎo)入頭文件就可以了

#import <PassKit/PassKit.h>                                 //用戶綁定的銀行卡信息
#import <PassKit/PKPaymentAuthorizationViewController.h>    //Apple pay的展示控件
#import <AddressBook/AddressBook.h>                         //用戶聯(lián)系信息相關(guān)

設(shè)備Applepay權(quán)限檢測(cè)

    if (![PKPaymentAuthorizationViewController class]) {
        //PKPaymentAuthorizationViewController需iOS8.0以上支持
        NSLog(@"操作系統(tǒng)不支持ApplePay,請(qǐng)升級(jí)至9.0以上版本,且iPhone6以上設(shè)備才支持");
        return;
    }
    //檢查當(dāng)前設(shè)備是否可以支付
    if (![PKPaymentAuthorizationViewController canMakePayments]) {
        //支付需iOS9.0以上支持
        NSLog(@"設(shè)備不支持ApplePay,請(qǐng)升級(jí)至9.0以上版本,且iPhone6以上設(shè)備才支持");
        return;
    }
    //檢查用戶是否可進(jìn)行某種卡的支付,是否支持Amex、MasterCard、Visa與銀聯(lián)四種卡,根據(jù)自己項(xiàng)目的需要進(jìn)行檢測(cè)
    NSArray *supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard,PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay];
    if (![PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:supportedNetworks]) {
        NSLog(@"沒有綁定支付卡");
        return;
    }

創(chuàng)建支付請(qǐng)求PKPaymentRequest

  • 初始化PKPaymentRequest
    這里需要注意RMB的幣種代碼是CNY
//設(shè)置幣種、國(guó)家碼及merchant標(biāo)識(shí)符等基本信息
    PKPaymentRequest *payRequest = [[PKPaymentRequest alloc]init];
    payRequest.countryCode = @"CN";     //國(guó)家代碼
    payRequest.currencyCode = @"CNY";       //RMB的幣種代碼
    payRequest.merchantIdentifier = @"merchant.ApplePayDemoYasin";  //申請(qǐng)的merchantID
    payRequest.supportedNetworks = supportedNetworks;   //用戶可進(jìn)行支付的銀行卡
    payRequest.merchantCapabilities = PKMerchantCapability3DS|PKMerchantCapabilityEMV;      //設(shè)置支持的交易處理協(xié)議,3DS必須支持,EMV為可選,目前國(guó)內(nèi)的話還是使用兩者吧
  • 設(shè)置發(fā)票配送信息和貨物配送地址信息,用戶設(shè)置后可以通過代理回調(diào)代理獲取信息的更新
//    payRequest.requiredBillingAddressFields = PKAddressFieldEmail;   
//如果需要郵寄賬單可以選擇進(jìn)行設(shè)置,默認(rèn)PKAddressFieldNone(不郵寄賬單)
//樓主感覺賬單郵寄地址可以事先讓用戶選擇是否需要,否則會(huì)增加客戶的輸入麻煩度,體驗(yàn)不好,
    payRequest.requiredShippingAddressFields = PKAddressFieldPostalAddress|PKAddressFieldPhone|PKAddressFieldName;
    //送貨地址信息,這里設(shè)置需要地址和聯(lián)系方式和姓名,如果需要進(jìn)行設(shè)置,默認(rèn)PKAddressFieldNone(沒有送貨地址)
送貨信息頁(yè)面展示
  • 設(shè)置貨物的配送方式,不需要不配置
//設(shè)置兩種配送方式
    PKShippingMethod *freeShipping = [PKShippingMethod summaryItemWithLabel:@"包郵" amount:[NSDecimalNumber zero]];
    freeShipping.identifier = @"freeshipping";
    freeShipping.detail = @"6-8 天 送達(dá)";
    
    PKShippingMethod *expressShipping = [PKShippingMethod summaryItemWithLabel:@"極速送達(dá)" amount:[NSDecimalNumber decimalNumberWithString:@"10.00"]];
    expressShipping.identifier = @"expressshipping";
    expressShipping.detail = @"2-3 小時(shí) 送達(dá)";
    
    payRequest.shippingMethods = @[freeShipping, expressShipping];
ApplePayiPhone2.png
ApplePayiPhone3.png
  • 賬單信息的設(shè)置
  • 每條賬單的設(shè)置
    賬單列表使用PKPaymentSummaryItem添加描述和價(jià)格,價(jià)格使用NSDecimalNumber。
    PKPaymentSummaryItem初始化:
    label為商品名字或者是描述,amount為商品價(jià)格,折扣為負(fù)數(shù),type為該條賬單為最終價(jià)格還是估算價(jià)格(比如出租車價(jià)格預(yù)估)
    + (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount;
    + (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount type:(PKPaymentSummaryItemType)type NS_AVAILABLE(NA, 9_0);
  • NSDecimalNumber初始化:
    NSDecimalNumber可以使用數(shù)字初始化,也可以使用字符串。
    使用方法請(qǐng)移步我寫的NSDecimalNumber--十進(jìn)制數(shù)
  • 添加賬單列表:
    NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO];   //12.75
    PKPaymentSummaryItem *subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@"商品價(jià)格" amount:subtotalAmount];
    
    NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithString:@"-12.74"];      //-12.74
    PKPaymentSummaryItem *discount = [PKPaymentSummaryItem summaryItemWithLabel:@"優(yōu)惠折扣" amount:discountAmount];
    
    NSDecimalNumber *methodsAmount = [NSDecimalNumber zero];
    PKPaymentSummaryItem *methods = [PKPaymentSummaryItem summaryItemWithLabel:@"包郵" amount:methodsAmount];
    
    NSDecimalNumber *totalAmount = [NSDecimalNumber zero];
    totalAmount = [totalAmount decimalNumberByAdding:subtotalAmount];
    totalAmount = [totalAmount decimalNumberByAdding:discountAmount];
    totalAmount = [totalAmount decimalNumberByAdding:methodsAmount];
    PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"Yasin" amount:totalAmount];  //最后這個(gè)是支付給誰。哈哈,快支付給我
    
    summaryItems = [NSMutableArray arrayWithArray:@[subtotal, discount, methods, total]];
//summaryItems為賬單列表,類型是 NSMutableArray,這里設(shè)置成成員變量,在后續(xù)的代理回調(diào)中可以進(jìn)行支付金額的調(diào)整。
    payRequest.paymentSummaryItems = summaryItems;

顯示購(gòu)物信息并進(jìn)行支付

//ApplePay控件
    PKPaymentAuthorizationViewController *view = [[PKPaymentAuthorizationViewController alloc]initWithPaymentRequest:payRequest];
    view.delegate = self;
    [self presentViewController:view animated:YES completion:nil];

PKPaymentAuthorizationViewControllerDelegate代理

  • 這里還有兩個(gè)類要介紹
  • PKPayment 支付成功信息
    PKPaymentToken *payToken = payment.token;
    //支付憑據(jù),發(fā)給服務(wù)端進(jìn)行驗(yàn)證支付是否真實(shí)有效
    PKContact *billingContact = payment.billingContact;     //賬單信息
    PKContact *shippingContact = payment.shippingContact;   //送貨信息
    PKContact *shippingMethod = payment.shippingMethod;     //送貨方式
  • PKContact 聯(lián)系人信息
    NSPersonNameComponents *name = contact.name;                //聯(lián)系人姓名
    CNPostalAddress *postalAddress = contact.postalAddress;     //聯(lián)系人地址
    NSString *emailAddress = contact.emailAddress;              //聯(lián)系人郵箱
    CNPhoneNumber *phoneNumber = contact.phoneNumber;           //聯(lián)系人手機(jī)
    NSString *supplementarySubLocality = contact.supplementarySubLocality;  //補(bǔ)充信息,地址詳細(xì)描述,其他備注等等,iOS9.2及以上才有
  • 代理說明
    送貨地址回調(diào)
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                  didSelectShippingContact:(PKContact *)contact
                                completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<PKShippingMethod *> * _Nonnull, NSArray<PKPaymentSummaryItem *> * _Nonnull))completion{
    //contact送貨地址信息,PKContact類型
    //送貨信息選擇回調(diào),如果需要根據(jù)送貨地址調(diào)整送貨方式,比如普通地區(qū)包郵+極速配送,偏遠(yuǎn)地區(qū)只有付費(fèi)普通配送,進(jìn)行支付金額重新計(jì)算,可以實(shí)現(xiàn)該代理,返回給系統(tǒng):shippingMethods配送方式,summaryItems賬單列表,如果不支持該送貨信息返回想要的PKPaymentAuthorizationStatus
    completion(PKPaymentAuthorizationStatusSuccess, shippingMethods, summaryItems);
}

送貨方式回調(diào)

-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                   didSelectShippingMethod:(PKShippingMethod *)shippingMethod
                                completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<PKPaymentSummaryItem *> * _Nonnull))completion{
    //配送方式回調(diào),如果需要根據(jù)不同的送貨方式進(jìn)行支付金額的調(diào)整,比如包郵和付費(fèi)加速配送,可以實(shí)現(xiàn)該代理
    PKShippingMethod *oldShippingMethod = [summaryItems objectAtIndex:2];
    PKPaymentSummaryItem *total = [summaryItems lastObject];
    total.amount = [total.amount decimalNumberBySubtracting:oldShippingMethod.amount];
    total.amount = [total.amount decimalNumberByAdding:shippingMethod.amount];
    
    [summaryItems replaceObjectAtIndex:2 withObject:shippingMethod];
    [summaryItems replaceObjectAtIndex:3 withObject:total];
    
    completion(PKPaymentAuthorizationStatusSuccess, summaryItems);
}

支付卡選擇回調(diào)

-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod completion:(void (^)(NSArray<PKPaymentSummaryItem *> * _Nonnull))completion{
    //支付銀行卡回調(diào),如果需要根據(jù)不同的銀行調(diào)整付費(fèi)金額,可以實(shí)現(xiàn)該代理
    completion(summaryItems);
}

送貨地址回調(diào),已棄用

-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectShippingAddress:(ABRecordRef)address completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<PKShippingMethod *> * _Nonnull, NSArray<PKPaymentSummaryItem *> * _Nonnull))completion{
    //送貨地址回調(diào),已棄用
}

付款成功蘋果服務(wù)器返回信息回調(diào),做服務(wù)器驗(yàn)證

-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                       didAuthorizePayment:(PKPayment *)payment
                                completion:(void (^)(PKPaymentAuthorizationStatus status))completion {
    PKPaymentToken *payToken = payment.token;
    //支付憑據(jù),發(fā)給服務(wù)端進(jìn)行驗(yàn)證支付是否真實(shí)有效
    PKContact *billingContact = payment.billingContact;     //賬單信息
    PKContact *shippingContact = payment.shippingContact;   //送貨信息
    PKContact *shippingMethod = payment.shippingMethod;     //送貨方式
    //等待服務(wù)器返回結(jié)果后再進(jìn)行系統(tǒng)block調(diào)用
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //模擬服務(wù)器通信
        completion(PKPaymentAuthorizationStatusSuccess);
    });
}

支付完成回調(diào)

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

demo的話因?yàn)樽C書問題可能會(huì)報(bào)錯(cuò),不過大家可以看看代碼。
demo下載

著作權(quán)歸作者所有。
商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
作者:Yasin

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容