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

    }

  • 相关阅读:
    跨数据库操作
    Windows 服务
    Linq To DataTable
    嵌入式软件应用程序开发框架浅见
    31.获取当前系统时间
    30 System类
    29. StringBuilder
    28. string类中方法练习
    27 string类中常用的方法列表
    26.String类(1)
  • 原文地址:https://www.cnblogs.com/liuluoxing/p/6485595.html
Copyright © 2020-2023  润新知