运行环境##
iphone 6 以及以上,iOS 9.2 以上。目前不支持企业证书添加。
支持模拟器测试。
环境配置##
1、 Xcode 7.2.1 以及以上打开项目,在 Capabilities里将Apple Pay设置为on,如下图,请忽略 Merchant IDmerchant.com.Carman.Paydemo这一项,一会我会详细介绍。
这时你会发现 项目 下 会自动 生成一个 类似证书的东西
这一步做了什么?
1、自动导入了需要的库文件。
2、添加了一个权限文件(图片-2).
2、 图一我们看到了有个 Merchant ID 选项,而且新建时候是没有配置的,那么需要到哪里去配置呢?
1、访问苹果开发账号,证书中心。
Identifiers -->Merchant IDs
输入描述 和 ID,ID 必须以merchant. 开头
Continue 到下一步,前方高能警报,嘀嘀嘀~~~~ 坑一出现:报错!!!!!!!
说明苹果对这个ID 格式是有要求的。多试几次。其实仔细看 图 -3 底下有一行小字, We recommend using a reverse-domain name style string (i.e.,merchant.com.example.merchantname). 最好按照官方要求 merchant.com.example.merchantname 这个格式来。
一步一步往下走。
这时候 会提示你 Identifier:merchant.com.Demo.applepaydemo已经生成。
点击 Done
根据上面的提示,点击Edit,接下去应该是需要建证书了。
首次添加时候 会询问你是否 在中国使用。选择 YES(截图是默认状态-NO),一直 continue 。
3、新建证书
创建 ** Creating a Certificate Signing Request (CSR) CSR 证书,**
Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.
打开钥匙串访问 如下图操作
生成 CertificateSigningRequest.certSigningRequest(名称可以自定义)
上传 生成证书
满怀信心,觉得即将成功是么?
此证书是由未知颁发机构签名的!!!什么鬼呀,老子的账号明明是正规渠道申请的!
还好有解决方案--- 点我解决.
点击下载红线项,删除老的证书,重新导入 G2 证书
以上,ApplePay 所需的环境就算全部配置完成了。
总结一下就一条: 生成了 Merchant ID 证书。
再看 项目 工程,已经自动生成了 Merchant ID 值,打钩就可以了,如果没有生成,再检查下 项目的 Bundle identifier是否和证书一致。
代码集成##
首先我们来看下模拟器上Demo 运行的结果:
这里要说的 重点不在下半部分,而是 Buy with XXPay 这个按钮,我们知道苹果是一个有情(偏)怀(执)的处女座公司,对很多的设计或则交互都有自己的一套规则,ApplePay 的响应 按钮也不例外。不要以为随便 弄个 设计个按钮 就能上线了,这个时候 美工和老板说了都不算,要听苹果的 ApplePay 设计规范。不然审核也过不了。
1、
导入头文件,(xcode 7.0 以上已经自动帮我们导入了库,所以我们只需要导入头文件即可)
#import
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;
// 添加联系人邮箱 及送货地址信息
//request.requiredShippingAddressFields = PKAddressFieldAll;
PKPaymentAuthorizationViewController *paymentPane =
[[PKPaymentAuthorizationViewController alloc]
initWithPaymentRequest:request];
paymentPane.delegate = self;
[self presentViewController:paymentPane animated:TRUE completion:nil];
} else {
NSLog(@"设备不支持支付");
}
}
1、[PKPaymentAuthorizationViewController canMakePayments] 判断设备支持不支持 ApplePay。中国区 是 iphone 6 及以上,iOS9.2
2、canMakePaymentsUsingNetworks: 判断 设备上用户有没有添加银行卡,如果没添加,不写这个判断,真机上会crash。
PKPaymentNetworkChinaUnionPay //中国银联卡
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查询网站
5、currencyCode 支付币种 ,人民币 CHW
6、supportedNetworks 能支持的卡种,同 2
7、merchantIdentifier ,终于出现这货了,申请半天的 Merchant ID ,请注意保持一致。
8、merchantCapabilities 询问你的付款处理器
PKMerchantCapabilityCredit //支持信用卡
PKMerchantCapabilityDebit //支持借记卡
9、requiredShippingAddressFields 添加联系人信息
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、调起 ** PKPaymentAuthorizationViewController**
PKPaymentAuthorizationViewController *paymentPane =
[[PKPaymentAuthorizationViewController alloc]
initWithPaymentRequest:request];
paymentPane.delegate = self;
[self presentViewController:paymentPane animated:TRUE completion:nil];
当然,我们要实现
@interface ViewController : UIViewController
@end
实现 PKPaymentAuthorizationViewControllerDelegate##
必须实现的两个代理:
#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
支付 状态回调在这里处理,支付成功和失败,订单的地址 以及和 服务器传输数据-token。
2、paymentAuthorizationViewControllerDidFinish:支付结束,关闭 支付弹框。
3、可选的另外的代理 回调 请参考Apple Pay接入详细教程 一文
我们主要来看下** PKPayment** 对象
token 支付成功之后的回执,需要上传给服务器。
billingAddress 用户账单地址
billingContact 用户账单信息
shippingAddress 送货地址
shippingContact 送货信息
shippingMethod 送货方式
以上的 信息 可以根据自己的需求 上传到服务器
- (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 代码集成,假设回调的信息也成功上传 服务器,服务器也成功对订单进行了处理,那么用户支付的钱去哪了?
1、钱去了商家的 AppStore 账号?
苹果账号的申请一般都是用信用卡支付 ,业务的收入不太可能直接打到信用卡里。
2、商家 AppStore 账号绑定了商家的银行卡?
我们生成 Merchant ID 证书的时候 并没有这一步。
支付供应商##
苹果官方文档 Apple Pay 入门 明确指出:
就是说,苹果官方强烈建议开发者接入他合作的支付供应商SDK 来支持ApplePay,这样就能理解了,开发者到支付供应商网站注册相关信息,绑定商户ID ,银行卡等,这样用户的钱就到了商户在支付供应商注册的账号里面。我们可以把支付供应商 理解成付款处理结构。 坑爹呀,上面的集成都白写了!!!
苹果官方在中国合作的指定付款处理结构有 (参考ApplePay 介绍):
中国银联
连连支付
首信易支付
易宝支付
银联商务
这里选择中国银联的sdk 进行介绍,有兴趣的同学可以自行去研究另外几个供应商的支付SDK。
中国银联##
选择中国银联 接入 有个很大的好处 -- 文档非常的详细。
1、中国银联商户入网新手指南
https://merchant.unionpay.com/join/help/director
2、银联商家服务
https://open.unionpay.com/ajweb/product/detail?id=80
3、银联Apple Pay控件开发包
https://open.unionpay.com/ajweb/help/file/techFile?productId=80
银联Apple Pay控件开发包####
下载 银联的Apple Pay 控件开发包,里面有非常详细的 介绍,如何接入ApplePay。
银联支付控件 SDK 模式 Apple Pay 支付的实现方式###
1-2、 商户生成订单,通过商户SERVER端将订单信息发送给银联支付网关;
3-4、银联支付网关记录订单信息,返回用来标识订单的 TN 号,经由商户 SERVER 返回至给商户 APP;
5、 商户 APP 调用银联 SDK,将 TN 号传递给银联 SDK
6、 银联 SDK 向 Apple 公司的 PASSKIT FRAMEWORK 发起支付请求;
7、 接口返回加密的支付 Token 信息;
8-9、银联 SDK 将支付 Token 传递给银联支付网关,完成交易认证;
10-12、银联将支付结果返回给商户 APP,商户 SERVER,商户 APP 负责提示用户交易结果。
集成的测试代码介绍##
1-2步、商户生成订单,通过商户SERVER端将订单信息发送给银联支付网关; 代码如下:
- (void) pmPayAction:(id)sender {
//使用PM环境
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"; //接入模式,标识商户以何种方式调用支付控件,00生产环境,01测试环境
2、http://101.231.204.84:8091/sim/getacptn //银联提供测试的 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 //接入模式,标识商户以何种方式调用支付控件,00生产环境,01测试环境
3、kAppleMerchantID //苹果公司分配的商户号,表示调用Apple Pay所需要的MerchantID;(接入银联支付时候,该 MerchantID 需要商家向银联申请生成)
10-12步,银联将支付结果返回给商户 APP,商户 SERVER,商户 APP 负责提示用户交易结果。 回调处理。
#pragma mark -
#pragma mark 响应控件返回的支付结果
#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表示发起支付以后用户取消,导致支付状态不确认,需要查询商户后台确认真实的支付结果
NSString *errorInfo = [NSString stringWithFormat:@"支付过程中用户取消了,请查询后台确认订单"];
[self showAlertMessage:errorInfo];
}
}