iOS三方支付--微信支付/支付寶支付

1、微信支付

1.註冊帳號並申請app支付功能

公司須要到微信開放品臺進行申請app支付功能 , 得到appid和微信支付商戶號(mch_id)和API祕鑰(key) 、 Appsecret(secret),開發中用到的,很重要html

  • appid:appid是微信公衆帳號或開放平臺APP的惟一標識,在公衆平臺申請公衆帳號或者在開放平臺申請APP帳號後,微信會自動分配對應的appid,用於標識該應用。可json

   在微信公衆平臺-->開發者中心查看,商戶的微信支付審覈經過郵件中也會包含該字段值。安全

  • 微信支付商戶號:商戶申請微信支付後,由微信支付分配的商戶收款帳號。服務器

  • 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,以下圖:app

  

b. 設置微信白名單

  

3.微信支付流程

  在集成微信支付以前應先了解微信支付的整個流程,微信支付總體流程圖以下:

  

  步驟1:用戶在商戶APP中選擇商品,提交訂單,選擇微信支付。微信公衆平臺

  步驟2:商戶後臺收到用戶支付單,調用微信支付統一下單接口。ide

  步驟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;
       }
    }
} 

2、支付寶支付

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];
            }
        }
    }];

3、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]];

}

相關文章
相關標籤/搜索