運(yùn)行環(huán)境##
iphone 6 以及以上,iOS 9.2 以上。目前不支持企業(yè)證書添加。
支持模擬器測試。
環(huán)境配置##
1、 Xcode 7.2.1 以及以上打開項(xiàng)目,在 Capabilities里將Apple Pay設(shè)置為on,如下圖,請忽略 Merchant IDmerchant.com.Carman.Paydemo這一項(xiàng),一會(huì)我會(huì)詳細(xì)介紹。

這時(shí)你會(huì)發(fā)現(xiàn) 項(xiàng)目 下 會(huì)自動(dòng) 生成一個(gè) 類似證書的東西

這一步做了什么?
1、自動(dòng)導(dǎo)入了需要的庫文件。
2、添加了一個(gè)權(quán)限文件(圖片-2).
2、 圖一我們看到了有個(gè) Merchant ID 選項(xiàng),而且新建時(shí)候是沒有配置的,那么需要到哪里去配置呢?
1、訪問蘋果開發(fā)賬號(hào),證書中心。
Identifiers -->Merchant IDs
輸入描述 和 ID,ID 必須以merchant. 開頭

Continue 到下一步,前方高能警報(bào),嘀嘀嘀~~~~ 坑一出現(xiàn):報(bào)錯(cuò)?。。。。。。?br>

說明蘋果對這個(gè)ID 格式是有要求的。多試幾次。其實(shí)仔細(xì)看 圖 -3 底下有一行小字,We recommend using a reverse-domain name style string (i.e.,merchant.com.example.merchantname). 最好按照官方要求 merchant.com.example.merchantname 這個(gè)格式來。

一步一步往下走。
這時(shí)候 會(huì)提示你 Identifier:merchant.com.Demo.applepaydemo已經(jīng)生成。

點(diǎn)擊 Done

根據(jù)上面的提示,點(diǎn)擊Edit,接下去應(yīng)該是需要建證書了。
首次添加時(shí)候 會(huì)詢問你是否 在中國使用。選擇 YES(截圖是默認(rèn)狀態(tài)-NO),一直 continue 。

3、新建證書
創(chuàng)建 ** Creating a Certificate Signing Request (CSR) CSR 證書,**
Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.
打開鑰匙串訪問 如下圖操作

生成 CertificateSigningRequest.certSigningRequest(名稱可以自定義)

上傳 生成證書

滿懷信心,覺得即將成功是么?

此證書是由未知頒發(fā)機(jī)構(gòu)簽名的?。?!什么鬼呀,老子的賬號(hào)明明是正規(guī)渠道申請的!
還好有解決方案---點(diǎn)我解決.
點(diǎn)擊下載紅線項(xiàng),刪除老的證書,重新導(dǎo)入 G2 證書

以上,ApplePay 所需的環(huán)境就算全部配置完成了。
總結(jié)一下就一條:生成了 Merchant ID 證書。
再看 項(xiàng)目 工程,已經(jīng)自動(dòng)生成了 Merchant ID 值,打鉤就可以了,如果沒有生成,再檢查下 項(xiàng)目的 Bundle identifier是否和證書一致。

代碼集成##
首先我們來看下模擬器上Demo 運(yùn)行的結(jié)果:

這里要說的 重點(diǎn)不在下半部分,而是 Buy with XXPay 這個(gè)按鈕,我們知道蘋果是一個(gè)有情(偏)懷(執(zhí))的處女座公司,對很多的設(shè)計(jì)或則交互都有自己的一套規(guī)則,ApplePay 的響應(yīng) 按鈕也不例外。不要以為隨便 弄個(gè) 設(shè)計(jì)個(gè)按鈕 就能上線了,這個(gè)時(shí)候 美工和老板說了都不算,要聽蘋果的ApplePay 設(shè)計(jì)規(guī)范。不然審核也過不了。
1、
導(dǎo)入頭文件,(xcode 7.0 以上已經(jīng)自動(dòng)幫我們導(dǎo)入了庫,所以我們只需要導(dǎo)入頭文件即可)
#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;
// 添加聯(lián)系人郵箱 及送貨地址信息
//request.requiredShippingAddressFields = PKAddressFieldAll;
PKPaymentAuthorizationViewController *paymentPane =
[[PKPaymentAuthorizationViewController alloc]
initWithPaymentRequest:request];
paymentPane.delegate = self;
[self presentViewController:paymentPane animated:TRUE completion:nil];
} else {
NSLog(@"設(shè)備不支持支付");
}
}
1、[PKPaymentAuthorizationViewController canMakePayments] 判斷設(shè)備支持不支持 ApplePay。中國區(qū) 是 iphone 6 及以上,iOS9.2
2、canMakePaymentsUsingNetworks: 判斷 設(shè)備上用戶有沒有添加銀行卡,如果沒添加,不寫這個(gè)判斷,真機(jī)上會(huì)crash。
PKPaymentNetworkChinaUnionPay //中國銀聯(lián)卡
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查詢網(wǎng)站
5、currencyCode 支付幣種 ,人民幣 CHW
6、supportedNetworks 能支持的卡種,同 2
7、merchantIdentifier ,終于出現(xiàn)這貨了,申請半天的 Merchant ID ,請注意保持一致。
8、merchantCapabilities 詢問你的付款處理器
PKMerchantCapabilityCredit //支持信用卡
PKMerchantCapabilityDebit //支持借記卡
9、requiredShippingAddressFields 添加聯(lián)系人信息
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、調(diào)起 ** PKPaymentAuthorizationViewController**
PKPaymentAuthorizationViewController *paymentPane =
[[PKPaymentAuthorizationViewController alloc]
initWithPaymentRequest:request];
paymentPane.delegate = self;
[self presentViewController:paymentPane animated:TRUE completion:nil];
當(dāng)然,我們要實(shí)現(xiàn)<PKPaymentAuthorizationViewControllerDelegate> 代理
@interface ViewController : UIViewController<PKPaymentAuthorizationViewControllerDelegate>
@end
實(shí)現(xiàn) PKPaymentAuthorizationViewControllerDelegate##
必須實(shí)現(xiàn)的兩個(gè)代理:
#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
支付 狀態(tài)回調(diào)在這里處理,支付成功和失敗,訂單的地址 以及和 服務(wù)器傳輸數(shù)據(jù)-token。
2、paymentAuthorizationViewControllerDidFinish:支付結(jié)束,關(guān)閉 支付彈框。
3、可選的另外的代理 回調(diào) 請參考Apple Pay接入詳細(xì)教程 一文
我們主要來看下** PKPayment** 對象

token 支付成功之后的回執(zhí),需要上傳給服務(wù)器。
billingAddress 用戶賬單地址
billingContact 用戶賬單信息
shippingAddress 送貨地址
shippingContact 送貨信息
shippingMethod 送貨方式
以上的 信息 可以根據(jù)自己的需求 上傳到服務(wù)器
- (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 代碼集成,假設(shè)回調(diào)的信息也成功上傳 服務(wù)器,服務(wù)器也成功對訂單進(jìn)行了處理,那么用戶支付的錢去哪了?
1、錢去了商家的 AppStore 賬號(hào)?
蘋果賬號(hào)的申請一般都是用信用卡支付 ,業(yè)務(wù)的收入不太可能直接打到信用卡里。
2、商家 AppStore 賬號(hào)綁定了商家的銀行卡?
我們生成 Merchant ID 證書的時(shí)候 并沒有這一步。
支付供應(yīng)商##
蘋果官方文檔 Apple Pay 入門 明確指出:

就是說,蘋果官方強(qiáng)烈建議開發(fā)者接入他合作的支付供應(yīng)商SDK 來支持ApplePay,這樣就能理解了,開發(fā)者到支付供應(yīng)商網(wǎng)站注冊相關(guān)信息,綁定商戶ID ,銀行卡等,這樣用戶的錢就到了商戶在支付供應(yīng)商注冊的賬號(hào)里面。我們可以把支付供應(yīng)商 理解成付款處理結(jié)構(gòu)。 坑爹呀,上面的集成都白寫了!??!
蘋果官方在中國合作的指定付款處理結(jié)構(gòu)有 (參考ApplePay 介紹):
中國銀聯(lián)
連連支付
首信易支付
易寶支付
銀聯(lián)商務(wù)
這里選擇中國銀聯(lián)的sdk 進(jìn)行介紹,有興趣的同學(xué)可以自行去研究另外幾個(gè)供應(yīng)商的支付SDK。
中國銀聯(lián)##
選擇中國銀聯(lián) 接入 有個(gè)很大的好處 -- 文檔非常的詳細(xì)。
1、中國銀聯(lián)商戶入網(wǎng)新手指南
https://merchant.unionpay.com/join/help/director
2、銀聯(lián)商家服務(wù)
https://open.unionpay.com/ajweb/product/detail?id=80
3、銀聯(lián)Apple Pay控件開發(fā)包
https://open.unionpay.com/ajweb/help/file/techFile?productId=80
銀聯(lián)Apple Pay控件開發(fā)包####
下載 銀聯(lián)的Apple Pay 控件開發(fā)包,里面有非常詳細(xì)的 介紹,如何接入ApplePay。

銀聯(lián)支付控件 SDK 模式 Apple Pay 支付的實(shí)現(xiàn)方式###

1-2、 商戶生成訂單,通過商戶SERVER端將訂單信息發(fā)送給銀聯(lián)支付網(wǎng)關(guān);
3-4、銀聯(lián)支付網(wǎng)關(guān)記錄訂單信息,返回用來標(biāo)識(shí)訂單的 TN 號(hào),經(jīng)由商戶 SERVER 返回至給商戶 APP;
5、 商戶 APP 調(diào)用銀聯(lián) SDK,將 TN 號(hào)傳遞給銀聯(lián) SDK
6、 銀聯(lián) SDK 向 Apple 公司的 PASSKIT FRAMEWORK 發(fā)起支付請求;
7、 接口返回加密的支付 Token 信息;
8-9、銀聯(lián) SDK 將支付 Token 傳遞給銀聯(lián)支付網(wǎng)關(guān),完成交易認(rèn)證;
10-12、銀聯(lián)將支付結(jié)果返回給商戶 APP,商戶 SERVER,商戶 APP 負(fù)責(zé)提示用戶交易結(jié)果。
集成的測試代碼介紹##
1-2步、商戶生成訂單,通過商戶SERVER端將訂單信息發(fā)送給銀聯(lián)支付網(wǎng)關(guān); 代碼如下:
- (void) pmPayAction:(id)sender {
//使用PM環(huán)境
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"; //接入模式,標(biāo)識(shí)商戶以何種方式調(diào)用支付控件,00生產(chǎn)環(huán)境,01測試環(huán)境
2、http://101.231.204.84:8091/sim/getacptn //銀聯(lián)提供測試的 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 //接入模式,標(biāo)識(shí)商戶以何種方式調(diào)用支付控件,00生產(chǎn)環(huán)境,01測試環(huán)境
3、kAppleMerchantID //蘋果公司分配的商戶號(hào),表示調(diào)用Apple Pay所需要的MerchantID;(接入銀聯(lián)支付時(shí)候,該 MerchantID 需要商家向銀聯(lián)申請生成)

10-12步,銀聯(lián)將支付結(jié)果返回給商戶 APP,商戶 SERVER,商戶 APP 負(fù)責(zé)提示用戶交易結(jié)果。 回調(diào)處理。
#pragma mark -
#pragma mark 響應(yīng)控件返回的支付結(jié)果
#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表示發(fā)起支付以后用戶取消,導(dǎo)致支付狀態(tài)不確認(rèn),需要查詢商戶后臺(tái)確認(rèn)真實(shí)的支付結(jié)果
NSString *errorInfo = [NSString stringWithFormat:@"支付過程中用戶取消了,請查詢后臺(tái)確認(rèn)訂單"];
[self showAlertMessage:errorInfo];
}
}
運(yùn)行效果###

