iOS三方支付--微信支付/支付宝支付
一、微信支付
1.注册账号并申请app支付功能
公司需要到微信开放品台进行申请app支付功能 , 获得appid和微信支付商户号(mch_id)和API秘钥(key) 、 Appsecret(secret),开发中用到的,很重要
• appid:appid是微信公众账号或开放平台APP的唯一标识,在公众平台申请公众账号或者在开放平台申请APP账号后,微信会自动分配对应的appid,用于标识该应用。可
在微信公众平台-->开发者中心查看,商户的微信支付审核通过邮件中也会包含该字段值。
• 微信支付商户号:商户申请微信支付后,由微信支付分配的商户收款账号。
• API密钥: 交易过程生成签名的密钥,仅保留在商户系统和微信支付后台,不会在网络中传播。商户妥善保管该Key,切勿在网络中传输,不能在其他客户端中存储,保证
key不会被泄漏。商户可根据邮件提示登录微信商户平台进行设置。也可按一下路径设置:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
• App secret : AppSecret是APPID对应的接口密码,用于获取接口调用凭证access_token时使用。
2.搭建工程并配置
a.导入微信支付的SDK
b.设置URL Scheme
项目-->Info-->RUL Types,添加一个URL SChemes,内容为自己商户的APPID,如下图:
b. 设置微信白名单
3.微信支付流程
在集成微信支付之前应先了解微信支付的整个流程,微信支付整体流程图如下:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。
注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。
步骤5:商户后台接收支付通知。
步骤6:商户后台查询支付结果。
3.代码实现具体流程
a.请求接口,生成商户订单
请求后台接口,获取调取微信支付所需的关键参数:partnerid、prepayid、package、sign、timestamp、noncestr
b.注册APPID
[WXApi registerApp:self.wxAppID];//与URL Type中设置的保持一致
c.调起微信支付PayReq *request = [[PayReq alloc] init];
request.openID = self.wxAppKey; request.partnerId = parterId; request.prepayId = prePayId; request.package = package; request.nonceStr = nonceStr; request.timeStamp = [timestamp intValue]; request.sign = sign;
if (![WXApi sendReq:request]) {
//微信调起支付失败
}
d.支付结果回调
-(void)onResp:(BaseResp*)resp{ if ([respisKindOfClass:[PayRespclass]]){ PayResp*response=(PayResp*)resp; switch(response.errCode){ caseWXSuccess: //服务器端查询支付通知或查询API返回的结果再提示成功 NSlog(@"支付成功"); break; default: NSlog(@"支付失败,retcode=%d",resp.errCode); break; } } }
二、支付宝支付
1.支付宝SDK集成
a.将支付宝的SDK及bundle文件拖入工程
b. 导入依赖库
c.设置URL Schemes
这里设置的URL Scheme必须与payOrder方法中的Scheme保持一致
d.设置白名单
在info.plist 文件中如下设置
2.代码实现
a.生成订单信息及签名
这一步可以通过后台生成订单,直接返回订单字符串,或者移动端自己实例化一个订单对象,并生成订单字符串
//将商品信息赋予AlixPayOrder的成员变量 Order *order = [[Order alloc] init]; order.partner = partner; order.seller = seller; order.tradeNO = @"123456"; //订单ID(由商家自行制定) order.productName = @"太空杯"; //商品标题 order.productDescription = @"耐摔的太空杯"; //商品描述 order.amount = [NSString stringWithFormat:@"%.2f",0.01]; //商品价格 order.notifyURL = @"http://www.lanou3g.com"; //回调URL order.service = @"mobile.securitypay.pay"; order.paymentType = @"1"; order.inputCharset = @"utf-8"; order.itBPay = @"30m"; order.showUrl = @"m.alipay.com"; //应用注册scheme,在AlixPayDemo-Info.plist定义URL types NSString *appScheme = @"xiaohange"; //将商品信息拼接成字符串 NSString *orderSpec = [order description]; NSLog(@"orderSpec = %@",orderSpec); //获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode id<DataSigner> signer = CreateRSADataSigner(privateKey); NSString *signedString = [signer signString:orderSpec]; //将签名成功字符串格式化为订单字符串,请严格按照该格式 NSString *orderString = nil; if (signedString != nil) { orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"", orderSpec, signedString, @"RSA"]; //[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) { // NSLog(@"reslut = %@",resultDic); //}]; }
b.调起支付宝支付
[[AlipaySDK defaultService] payOrder:orderString fromScheme:@"669SDKAliPay" callback:^(NSDictionary *dict) { if (dict) { NSLog(@"%@",dict); NSInteger statusCode = [dict[@"resultStatus"] integerValue]; NSString *msg = [NSString stringValue:dict[@"memo"]]; if (statusCode == 9000) { [self performSelector:@selector(paymentSuccess) withObject:self.tradeNo afterDelay:0.25f]; } else if (statusCode == 6001) { [self performSelector:@selector(paymentCancel) withObject:self.tradeNo afterDelay:0.25f]; } else { [self performSelector:@selector(paymentErrorWithMessage:) withObject:msg afterDelay:0.25f]; } } }];
三、WanPaymentData集成
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #import "WXApi.h" #import <AlipaySDK/AlipaySDK.h> @protocol WanPaymentDataDelegate <NSObject> @optional - (void)paymentSuccess; - (void)paymentCancel; - (void)paymentResultWithError:(NSError *)error; @end typedef NS_OPTIONS(NSUInteger, WanPaymentType) { WanPaymentTypeAliPay = 2, //支付宝钱包 WanPaymentTypeWXPay = 1, //微信支付 WanPaymentTypeAliPayWAP = 102 //支付宝 WAP }; @interface WanPaymentData : NSObject <WXApiDelegate> { } @property (nonatomic, assign) WanPaymentType paymentType; @property (nonatomic, weak) id<WanPaymentDataDelegate> delegate; @property (nonatomic, weak) UIView *view; @property (nonatomic, copy) NSString *wxAppKey; @property (nonatomic, retain) NSString *tradeNo; //订单编号 @property (nonatomic, retain) NSString *paymentTradeNo; //支付编号 - 支付宝给的 @property (nonatomic, retain) NSString *productName; //订单名称 @property (nonatomic, retain) NSString *productDesc; //订单描述 @property (nonatomic, retain) NSString *productAmount; //订单单价 @property (nonatomic, retain) NSString *productEndTime; //订单结束时间 + (instancetype)instance; + (BOOL)canOpenPaymentApp:(WanPaymentType)paymentType; - (void)requestPaymentURLWithResult:(NSDictionary *)dict; - (void)paymentErrorWithMessage:(NSString *)errorMessage; - (BOOL)handleOpenURL:(NSURL *)url; //支付宝客户端回调 - (void)wxpayResultCode:(int)resultCode; //微信支付客户端回调 @end
#import "WanPaymentData.h" #import "NSString+Util.h" #import "AlixPayResult.h" //#import "PPUIUtils.h" //#import "UPPayPlugin.h" #import <YRJSONAdapter.h> #import "WanPayServer.h" #import "WanProgressHUD.h" static NSString *kPPPaymentURLForAliPay = @"alipay://alipayclient/"; static NSString *kPPGetPaymentURL = @"payment-pay/paySubmit"; static NSString *kPPPaymentParamAliPayClient = @"alipay_sdk"; //支付宝钱包 static NSString *kPPPaymentParamAliPayWAP = @"alipay_wap"; //支付宝网页 static NSString *kPPPaymentParamWXPayClient = @"wechat_sdk"; //微信客户端 #define kWeiXinWanAppKey @"wxb68956c81f8a2512" typedef NS_OPTIONS(NSUInteger, PPPaymentWCheckStatus) { PPPaymentCheckStatusOK = 1, //可以支付 PPPaymentCheckStatusAppNotInstalled = 2, //应用未安装 PPPaymentCheckStatusSignError = 3 //签名错误 }; @interface WanPaymentData () { WanPayServer *_payServer; } @end @implementation WanPaymentData + (instancetype)instance { static WanPaymentData *sharedInstance = nil; if (sharedInstance == nil) { sharedInstance = [[WanPaymentData alloc] init]; } return sharedInstance; } #pragma mark - Init #pragma mark - Class Method + (BOOL)canOpenPaymentApp:(WanPaymentType)paymentType { if (paymentType == WanPaymentTypeAliPay) { return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:kPPPaymentURLForAliPay]]; } else if (paymentType == WanPaymentTypeWXPay) { return [WXApi isWXAppInstalled]; } return NO; } #pragma mark - Request Payment URL - (void)requestPaymentURLWithResult:(NSDictionary *)dict { [WanProgressHUD hideAfterDelay:1.5]; NSInteger resultCode = [[NSString stringValue:dict[@"state"][@"code"]] integerValue]; NSString *resultMsg = [NSString stringValue:dict[@"state"][@"msg"]]; if (resultCode == 1) { if (self.paymentType == WanPaymentTypeAliPay) { NSString *paymentURL = [NSString stringValue:dict[@"data"][@"pay_info"]]; NSString *clientFlag = [NSString stringValue:dict[@"data"][@"order_no"]]; [self openAliPayClientWithPaymentURL:paymentURL clientFlag:clientFlag]; } else if (self.paymentType == WanPaymentTypeAliPayWAP) { NSString *paymentURL = [NSString stringValue:[dict valueForKeyPath:@"data.payment_url"]]; NSString *htmlCode = [NSString stringValue:[dict valueForKeyPath:@"data.payment_html"]]; NSDictionary *param = @{@"title" : @"支付宝网页支付", @"URL" : paymentURL, @"html" : htmlCode}; // [[NSNotificationCenter defaultCenter] postNotificationName:LMBNotificationKeyForShowPaymentWebPage object:param userInfo:nil]; } else if (self.paymentType == WanPaymentTypeWXPay) { // NSString *jsonString = [NSString stringValue:[dict valueForKeyPath:@"data.payment_wx"]]; // NSDictionary *param = [jsonString objectFromJSONString]; [self openWXClientWithPaymentURL:dict[@"data"][@"pay_info"]]; } }else{ [self paymentErrorWithMessage:resultMsg]; } } #pragma mark - Interface Method
//- (void)paymentWithType:(WanPaymentType)type
//{
// self.paymentType = type;
//
// if (self.paymentType == WanPaymentTypeAliPay) {
// NSMutableDictionary *params = [NSMutableDictionary dictionary];
// [params setObject:kPPPaymentParamAliPayClient forKey:@"payment_type"];
// [params setObject:self.tradeNo forKey:@"order_sn"];
// [self requestPaymentURLWithParam:[NSDictionary dictionaryWithDictionary:params]];
// }
// else if (self.paymentType == WanPaymentTypeAliPayWAP) {
// NSMutableDictionary *params = [NSMutableDictionary dictionary];
// [params setObject:kPPPaymentParamAliPayWAP forKey:@"payment_type"];
// [params setObject:self.tradeNo forKey:@"order_sn"];
// [self requestPaymentURLWithParam:[NSDictionary dictionaryWithDictionary:params]];
// }
// else if (self.paymentType == WanPaymentTypeWXPay) {
// NSMutableDictionary *params = [NSMutableDictionary dictionary];
// [params setObject:kPPPaymentParamWXPayClient forKey:@"payment_type"];
// [params setObject:self.tradeNo forKey:@"order_sn"];
// [self requestPaymentURLWithParam:[NSDictionary dictionaryWithDictionary:params]];
// }
//}
#pragma mark - Handler Method - (void)openAliPayClientWithPaymentURL:(NSString *)paymentURL clientFlag:(NSString *)clientFlag { [[AlipaySDK defaultService] payOrder:paymentURL fromScheme:@"669SDKAliPay" callback:^(NSDictionary *dict) { if (dict) { NSLog(@"%@",dict); NSInteger statusCode = [dict[@"resultStatus"] integerValue]; NSString *msg = [NSString stringValue:dict[@"memo"]]; if (statusCode == 9000) { [self performSelector:@selector(paymentSuccess) withObject:self.tradeNo afterDelay:0.25f]; } else if (statusCode == 6001) { [self performSelector:@selector(paymentCancel) withObject:self.tradeNo afterDelay:0.25f]; } else { [self performSelector:@selector(paymentErrorWithMessage:) withObject:msg afterDelay:0.25f]; } } }]; } //- (void)openUPMPClientWithPaymentSN:(NSString *)paymentSN //{ // UIViewController *controller = [[[UIApplication sharedApplication] keyWindow] rootViewController]; // // if (![UPPayPlugin startPay:paymentSN mode:@"00" viewController:controller delegate:self]) { // [self paymentErrorWithMessage:@"抱歉,无法加载银联控件,请关闭应用重试!"]; // } //} - (void)openWXClientWithPaymentURL:(NSDictionary *)paymentParams { NSString *parterId = [NSString stringValue:[paymentParams valueForKey:@"partnerid"]]; NSString *prePayId = [NSString stringValue:[paymentParams valueForKey:@"prepayid"]]; NSString *package = [NSString stringValue:[paymentParams valueForKey:@"package"]]; NSString *sign = [NSString stringValue:[paymentParams valueForKey:@"sign"]]; NSString *timestamp = [NSString stringValue:[paymentParams valueForKey:@"timestamp"]]; NSString *nonceStr = [NSString stringValue:[paymentParams valueForKey:@"noncestr"]]; self.wxAppKey = [NSString stringValue:[paymentParams valueForKey:@"appid"]]; if ([NSString isEmpty:parterId] || [NSString isEmpty:prePayId] || [NSString isEmpty:package] || [NSString isEmpty:sign] || [NSString isEmpty:timestamp] || [NSString isEmpty:nonceStr]) { [self paymentErrorWithMessage:@"缺少关键参数,无法执行微信支付!"]; return; } [WXApi registerApp:self.wxAppKey]; PayReq *request = [[PayReq alloc] init]; request.openID = self.wxAppKey; request.partnerId = parterId; request.prepayId = prePayId; request.package = package; request.nonceStr = nonceStr; request.timeStamp = [timestamp intValue]; request.sign = sign; if (![WXApi sendReq:request]) { [self paymentErrorWithMessage:@"抱歉,无法打开微信。请您安装最新版本微信"]; } } #pragma mark - 付款回调 - (void)paymentSuccess { if (self.delegate && [self.delegate respondsToSelector:@selector(paymentSuccess)]) { [self.delegate paymentSuccess]; } } - (void)paymentCancel { if (self.delegate && [self.delegate respondsToSelector:@selector(paymentCancel)]) { [self.delegate paymentCancel]; } } - (void)paymentErrorWithMessage:(NSString *)errorMessage { if (self.delegate && [self.delegate respondsToSelector:@selector(paymentResultWithError:)]) { [self.delegate paymentResultWithError:[NSError errorWithDomain:@"http://mobile.yx58.com/Api/Sdk/index" code:500 userInfo:@{NSLocalizedDescriptionKey:errorMessage}]]; } } // 支付宝客户端支付后回调 - (BOOL)handleOpenURL:(NSURL *)url { NSString *query = [[NSString getString:[url query]] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; if (![NSString isEmpty:query]) { AlixPayResult *result = [[AlixPayResult alloc] initWithResultString:query]; if (result.statusCode == 9000) { [self performSelector:@selector(paymentSuccess) withObject:self.tradeNo afterDelay:0.25f]; } else if (result.statusCode == 6001) { [self performSelector:@selector(paymentCancel) withObject:self.tradeNo afterDelay:0.25f]; } else { [self performSelector:@selector(paymentErrorWithMessage:) withObject:result.statusMessage afterDelay:0.25f]; } } return NO; } // 银联控件回调 - (void)UPPayPluginResult:(NSString *)result { if ([result isEqualToString:@"success"]) { [self performSelector:@selector(paymentSuccess) withObject:self.tradeNo afterDelay:0.25f]; } else if ([result isEqualToString:@"cancel"]) { [self performSelector:@selector(paymentCancel) withObject:self.tradeNo afterDelay:0.25f]; } else { [self performSelector:@selector(paymentErrorWithMessage:) withObject:result afterDelay:0.5f]; } } - (void)onResp:(BaseResp *)resp { // 微信支付返回处理 if ([resp isKindOfClass:[PayResp class]]) { PayResp *response = (PayResp *)resp; NSLog(@"Pay Responder Code = %zd", response.errCode); [self wxpayResultCode:response.errCode]; } } // 微信支付客户端回调 - (void)wxpayResultCode:(int)resultCode { NSString *errMsg = nil; if (resultCode == 0) { [self performSelector:@selector(paymentSuccess) withObject:self.tradeNo afterDelay:0.25f]; return; } else if (resultCode == -1) { errMsg = @"未知错误"; } else if (resultCode == -2) { errMsg = @"取消微信支付"; } else if (resultCode == -3) { errMsg = @"发送失败"; } else if (resultCode == -4) { errMsg = @"授权失败"; } else if (resultCode == -5) { errMsg = @"微信不支持"; } if (resultCode == -2) { [self performSelector:@selector(paymentCancel) withObject:self.tradeNo afterDelay:0.25f]; } else { [self performSelector:@selector(paymentErrorWithMessage:) withObject:@"微信支付失败" afterDelay:0.25f]; } } @end
1.在调用后台接口,生成订单成功后调用一下代码:
[[WanPaymentData instance] setDelegate:self]; [WanPaymentData instance].paymentType = paymentType; [[WanPaymentData instance] requestPaymentURLWithResult:dict];
2.遵守协议并实现代理方法:
#pragma mark --<WanPaymentDataDelegate> - (void)paymentSuccess{ [self removeFromSuperview]; if (self.paySuccessBlock) { self.paySuccessBlock(); } } - (void)paymentCancel{ [PPUIUtils showStateInWindow:@"您已放弃付款"]; } - (void)paymentResultWithError:(NSError *)error{ NSString *msg = [error localizedDescription]; [PPUIUtils showStateInWindow:msg]; }
3.在AppDelegate添加以下代码
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
if ([url.host isEqualToString:@"safepay"]) {
return [[WanPaymentData instance] handleOpenURL:[NSURL URLWithString:url.absoluteString]];
}
return [WXApi handleOpenURL:url delegate:[WanPaymentData instance]];
}
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(nonnull id)annotation{
if ([url.host isEqualToString:@"safepay"]) {
return [[WanPaymentData instance] handleOpenURL:[NSURL URLWithString:url.absoluteString]];
}
return [WXApi handleOpenURL:url delegate:[WanPaymentData instance]];
}
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
if ([url.host isEqualToString:@"safepay"]) {
return [[WanPaymentData instance] handleOpenURL:[NSURL URLWithString:url.absoluteString]];
}
return [WXApi handleOpenURL:url delegate:[WanPaymentData instance]];
}