Apple Pay運行環(huán)境:iPhone6以上裝備,操作系統(tǒng)最低iOS9.0以上,部份信息設(shè)置需要iOS9.2以上。目前還不支持企業(yè)證書添加。
環(huán)境搭建好后可以在摹擬器上面運行,xcode7.2.1+iPhone6SP9.2系統(tǒng)下,系統(tǒng)會綁定幾種虛擬的銀行卡,和幾個聯(lián)系人,方便調(diào)試,支付也不會產(chǎn)生真實的付款,真的很方便。
準備工作
在接入Apple Pay之前,首先要申請MerchantID及對應(yīng)證書。
工程設(shè)置
bundleID設(shè)置
Capability中啟用Apple Pay權(quán)限,并選擇merchantID。
以后項目會多1個Applepay的配置文件ApplePayYasin.entitlements
需要援用的庫
Xcode7.0以上不需要再手動添加需要援用的庫了,只需要導(dǎo)入頭文件就能夠了
1
2
3
|
#import <passkit passkit.h=""> //用戶綁定的銀行卡信息 #import <passkit pkpaymentauthorizationviewcontroller.h=""> //Apple pay的展現(xiàn)控件 #import <addressbook addressbook.h=""> //用戶聯(lián)系信息相干</addressbook></passkit></passkit> |
裝備Applepay權(quán)限檢測
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
if (![PKPaymentAuthorizationViewController class]) { //PKPaymentAuthorizationViewController需iOS8.0以上支持 NSLog(@ "操作系統(tǒng)不支持ApplePay,請升級至9.0以上版本,且iPhone6以上裝備才支持" ); return ; } //檢查當前裝備是不是可以支付 if (![PKPaymentAuthorizationViewController canMakePayments]) { //支付需iOS9.0以上支持 NSLog(@ "裝備不支持ApplePay,請升級至9.0以上版本,且iPhone6以上裝備才支持" ); return ; } //檢查用戶是不是可進行某種卡的支付,是不是支持Amex、MasterCard、Visa與銀聯(lián)4種卡,根據(jù)自己項目的需要進行檢測 NSArray *supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard,PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay]; if (![PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:supportedNetworks]) { NSLog(@ "沒有綁定支付卡" ); return ; } |
創(chuàng)建支付要求PKPaymentRequest
初始化PKPaymentRequest
這里需要注意RMB的幣種代碼是CNY
1
2
3
4
5
6
7
|
//設(shè)置幣種、國家碼及merchant標識符等基本信息 PKPaymentRequest *payRequest = [[PKPaymentRequest alloc]init]; payRequest.countryCode = @ "CN" ; //國家代碼 payRequest.currencyCode = @ "CNY" ; //RMB的幣種代碼 payRequest.merchantIdentifier = @ "merchant.ApplePayDemoYasin" ; //申請的merchantID payRequest.supportedNetworks = supportedNetworks; //用戶可進行支付的銀行卡 payRequest.merchantCapabilities = PKMerchantCapability3DS|PKMerchantCapabilityEMV; //設(shè)置支持的交易處理協(xié)議,3DS必須支持,EMV為可選,目前國內(nèi)的話還是使用二者吧 |
設(shè)置發(fā)票配送信息和貨物配送地址信息,用戶設(shè)置后可以通過代理回調(diào)代理獲得信息的更新
1
2
3
4
5
|
// payRequest.requiredBillingAddressFields = PKAddressFieldEmail; //如果需要郵寄賬單可以選擇進行設(shè)置,默許PKAddressFieldNone(不郵寄賬單) //樓主感覺賬單郵寄地址可以事前讓用戶選擇是不是需要,否則會增加客戶的輸入麻煩度,體驗不好, payRequest.requiredShippingAddressFields = PKAddressFieldPostalAddress|PKAddressFieldPhone|PKAddressFieldName; //送貨地址信息,這里設(shè)置需要地址和聯(lián)系方式和姓名,如果需要進行設(shè)置,默許PKAddressFieldNone(沒有送貨地址) |
送貨信息頁面展現(xiàn)
設(shè)置貨物的配送方式,不需要不配置
1
2
3
4
5
6
7
8
9
10
|
//設(shè)置兩種配送方式 PKShippingMethod *freeShipping = [PKShippingMethod summaryItemWithLabel:@ "包郵" amount:[NSDecimalNumber zero]]; freeShipping.identifier = @ "freeshipping" ; freeShipping.detail = @ "6⑻ 天 投遞" ; PKShippingMethod *expressShipping = [PKShippingMethod summaryItemWithLabel:@ "極速投遞" amount:[NSDecimalNumber decimalNumberWithString:@ "10.00" ]]; expressShipping.identifier = @ "expressshipping" ; expressShipping.detail = @ "2⑶ 小時 投遞" ; payRequest.shippingMethods = @[freeShipping, expressShipping]; |
賬單信息的設(shè)置
每條賬單的設(shè)置
賬單列表使用PKPaymentSummaryItem添加描寫和價格,價格使用NSDecimalNumber。
PKPaymentSummaryItem初始化:
label為商品名字或是描寫,amount為商品價格,折扣為負數(shù),type為該條賬單為終究價格還是估算價格(比如出租車價格預(yù)估)
1
2
|
+ (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ù)字初始化,也能夠使用字符串。
使用方法請移步我寫的NSDecimalNumber--10進制數(shù)
添加賬單列表:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:⑵ isNegative:NO]; //12.75 PKPaymentSummaryItem *subtotal = [PKPaymentSummaryItem summaryItemWithLabel:@ "商品價格" amount:subtotalAmount]; NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithString:@ "⑴2.74" ]; //⑴2.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]; //最后這個是支付給誰。哈哈,快支付給我 summaryItems = [NSMutableArray arrayWithArray:@[subtotal, discount, methods, total]]; //summaryItems為賬單列表,類型是 NSMutableArray,這里設(shè)置成成員變量,在后續(xù)的代理回調(diào)中可以進行支付金額的調(diào)劑。 payRequest.paymentSummaryItems = summaryItems; |
顯示購物信息并進行支付
1
2
3
4
|
//ApplePay控件 PKPaymentAuthorizationViewController *view = [[PKPaymentAuthorizationViewController alloc]initWithPaymentRequest:payRequest]; view.delegate = self; [self presentViewController:view animated:YES completion:nil]; |
PKPaymentAuthorizationViewControllerDelegate代理
這里還有兩個類要介紹
PKPayment 支付成功信息
1
2
3
4
5
|
PKPaymentToken *payToken = payment.token; //支付憑據(jù),發(fā)給服務(wù)端進行驗證支付是不是真實有效 PKContact *billingContact = payment.billingContact; //賬單信息 PKContact *shippingContact = payment.shippingContact; //送貨信息 PKContact *shippingMethod = payment.shippingMethod; //送貨方式 |
PKContact 聯(lián)系人信息
1
2
3
4
5
|
NSPersonNameComponents *name = contact.name; //聯(lián)系人姓名 CNPostalAddress *postalAddress = contact.postalAddress; //聯(lián)系人地址 NSString *emailAddress = contact.emailAddress; //聯(lián)系人郵箱 CNPhoneNumber *phoneNumber = contact.phoneNumber; //聯(lián)系人手機 NSString *supplementarySubLocality = contact.supplementarySubLocality; //補充信息,地址詳細描寫,其他備注等等,iOS9.2及以上才有 |
代理說明
送貨地址回調(diào)
1
2
3
4
5
6
7
|
-(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ū)包郵+極速配送,偏僻地區(qū)只有付費普通配送,進行支付金額重新計算,可以實現(xiàn)該代理,返回給系統(tǒng):shippingMethods配送方式,summaryItems賬單列表,如果不支持該送貨信息返回想要的PKPaymentAuthorizationStatus completion(PKPaymentAuthorizationStatusSuccess, shippingMethods, summaryItems); }</pkpaymentsummaryitem *></pkshippingmethod *> |
送貨方式回調(diào)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectShippingMethod:(PKShippingMethod *)shippingMethod completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<pkpaymentsummaryitem *> * _Nonnull))completion{ //配送方式回調(diào),如果需要根據(jù)不同的送貨方式進行支付金額的調(diào)劑,比如包郵和付費加速配送,可以實現(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); }</pkpaymentsummaryitem *> |
支付卡選擇回調(diào)
1
2
3
4
|
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod completion:(void (^)(NSArray<pkpaymentsummaryitem *> * _Nonnull))completion{ //支付銀行卡回調(diào),如果需要根據(jù)不同的銀行調(diào)劑付費金額,可以實現(xiàn)該代理 completion(summaryItems); }</pkpaymentsummaryitem *> |
送貨地址回調(diào),已棄用
1
2
3
|
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectShippingAddress:(ABRecordRef)address completion:(void (^)(PKPaymentAuthorizationStatus, NSArray<pkshippingmethod *> * _Nonnull, NSArray<pkpaymentsummaryitem *> * _Nonnull))completion{ //送貨地址回調(diào),已棄用 }</pkpaymentsummaryitem *></pkshippingmethod *> |
付款成功蘋果服務(wù)器返回信息回調(diào),做服務(wù)器驗證
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
-(void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus status))completion { PKPaymentToken *payToken = payment.token; //支付憑據(jù),發(fā)給服務(wù)端進行驗證支付是不是真實有效 PKContact *billingContact = payment.billingContact; //賬單信息 PKContact *shippingContact = payment.shippingContact; //送貨信息 PKContact *shippingMethod = payment.shippingMethod; //送貨方式 //等待服務(wù)器返回結(jié)果后再進行系統(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)
1
2
3
|
-(void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller{ [controller dismissViewControllerAnimated:YES completion:nil]; } |