一、微信支付
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]];
}