美文网首页iOS开发好文平时生活和工作中的iOSiOS开发
我的天呐🙈,怎么会有这么详细的微信支付说明

我的天呐🙈,怎么会有这么详细的微信支付说明

作者: 三粒黑子球 | 来源:发表于2016-05-02 16:38 被阅读4559次

    公司要求项目添加上微信支付和支付宝支付在这里我将自己的心得以及自己总结的步骤总结在这里,希望让读者少一点入坑。,那么我们现在从最难的骨头啃起来,一步步教大家完成微信支付,关于申请微信支付的东西我就不再这里累赘,很多帖子都有(其实是因为公司这部分我没有参与,嘿嘿)。开始我们的微信支付的旅行吧。
    前提条件,让你的 APP有支付的本领 ,申请到微信支付相关以后,下面这些东西对我们很重要。

    前提条件:
    //APPID 一般以wx开头
    static NSString *const ZQAppID = @"APPID";
    //appsecret
    static NSString *const ZQAppSecret = @"appsecret";
    //商户号,填写商户对应参数
    static NSString *const ZQMchID = @"商户号";
    //商户API密钥,填写相应参数
    static NSString *const ZQPartnerID = @"商户API密钥";
    // 预支付请求路径固定可以不改变
    static NSString *const ZQPrePayURL =       @"https://api.mch.weixin.qq.com/pay/unifiedorder";
    // // 支付回调页面(异步)   (https://api.mch.weixin.qq.com/pay/unifiedorder)(异步处理支付调用返回数据)
    static NSString *const ZQPayNotifyURL = @"支付回调页面";
    
    注意

    微信支付的单位为分!!!整数类型才可以(int)

    流程简述

    支付要保证安全性,就要使用加密。微信当然也是这样,微信为了防止中间有人加入窃取信息或者改变价格。有自己的加密方式——生成预支付Id,我们通过封装数据形成XML格式(中间加密)以字符串类型传给微信,获取预支付Id。紧接着,获取以后通过预支付等信息再次加密。APP将参数传给微信,付款成功!回调信息说明支付情况。(关于加密具体怎么实现我会在下面详细说明)。

    步骤以及代码

    接下来说说主要的步骤吧(比比叨这么久终于说正事了,请不要打我么么哒~)


    H92X9S)M$J0XZQ@K13C0GVS.jpg

    1.在做微信支付以前导入

    libc++.tbd
    libsqlite3.0.tbd
    libz.tbd
    SystemConfiguration.framework
    CoreTelephony.framework
    Security.framework
    

    2.在AppDelegate 的导入头文件 #import "WXApi.h" 挂上代理 WXApiDelegate

     - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    //这里是你自己写的一些其他代码 实例化window 设置根视图云云
      [WXApi registerApp:@"APPID" withDescription:@"应用描述"];
    
      } 
     //支付回调
      - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
       return  [WXApi handleOpenURL:url delegate:self];
       }
      - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
       return [WXApi handleOpenURL:url delegate:self];
       }
    
    
       #pragma mark 微信回调的代理方法
       - (void)onResp:(BaseResp *)resp {
       if ([resp isKindOfClass:[PayResp class]]) {
       PayResp *response = (PayResp *)resp;
       switch (response.errCode) {
       case WXSuccess:
       NSLog(@"suceess");
       break;
       default:
       NSLog(@"failed");
       break;
       }
       }
       }
    

    如果集成里支付宝以及微信支付等 ,走的回调方法是相同的 ,我们是通过 回调中字符串sourceApplication 进行判断的 例如支付宝支付 为com.alipay.iphoneclient 微信支付为 com.tencent.xin

    3.在targets的info中添加 urltypes添加一个在 identifier自己起一个名称(最好软件英文名字) 在 URL schemes 中写下APPID

    E618D85B-4F5C-480B-96DA-6F4E9FE548A9.png

    4.触发支付
    触发支付,就要对自己的订单号价格等进行加密 在这里就可以分成两种加密 ,一种是在APP端进行加密,第二种是在服务端进行加密。一般使用的在服务端加密比较安全。一个个进行说明。
    4.1 服务端进行加密
    服务端加密我们不需要知道具体加密怎么进行的。(在底下我会给你说清楚的啦~)我们只是需要将所需参数传过去 我是用的AFN

    //初始化一个请求管理器
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    //接口地址
    NSString *urlString = [NSString stringWithFormat:@"%@%@",@"地址头",@"其他"];
    //参数字典
    NSDictionary *parameters =@{@"fcode": @"账号",
                                @"password": @"密码",@"out_trade_no":@"订单号",@"total_fee":@"金额(分为单位)",@"attach":@"商品详情"};
    //post请求
    [manager POST:urlString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
        //返回状态值1表示成功 0表示失败
        NSString *state=responseObject[@"state"];
       //预支付ID
        NSString *prepayid=responseObject[@"prepayid"];
       //返回文字信息成功或者失败
        NSString *message=responseObject[@"message"];
       //请求数据成功
            if ([state intValue]==1) {
       //支付信息
                PayReq* req             = [[PayReq alloc] init];
       //APPID
                req.openID              = [responseObject objectForKey:@"appid"];
       //商户号
                req.partnerId           = [responseObject objectForKey:@"partnerid"];
       //预支付ID
                req.prepayId            = [responseObject objectForKey:@"prepayid"];
       //时间戳
                req.nonceStr            = [responseObject objectForKey:@"noncestr"];
       //支付类型(为固定字符串:Sign=WXPay)
                req.timeStamp           = [[responseObject objectForKey:@"timestamp"] intValue];
       //加密串
                req.package             = [responseObject objectForKey:@"package"];
       //预支付ID
                req.sign                = [responseObject objectForKey:@"sign"];
                
                // 发起微信支付
                [WXApi sendReq:req];;
                
            }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    
    }];
    

    后台没有加密错误,那么会跳转到微信上进行支付。(好累啊 怎么还不结束呀)
    4.2 APP端进行加密
    这种方法可以自己先进行测试 ,或者为了缩短工期自己进行所有工作。(看起来好像好厉害的样子啊 )
    首先,下载文章最底部封装的微信支付文件,导入到工程中。
    支付界面引入头文件
    #import "ZQPay.h"
    在触发支付的方法中调用

    [ZQPay payWXWithOrderName:@"订单名字(不是订单详情)" price:@"订单价格(单位为分)" tradeNo:@"订单号" attach:@"订单详情"]
    

    调用支付成功!结束 (我说了“结束”一定会打我的吧,原理步骤都不说 这太敷衍了 哈哈哈 ,你们来打我啊)

    ![ZH]0RDFI%M7FXPS`(0FBEUE.jpg](https://img.haomeiwen.com/i1141241/53e22ffdd4735dac.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    (啊!!!不要打我 我说还不行吗)
    继续正题!
    传入参数我具体做了一些什么呢现在我就说说 步骤了啊(我不会就这样轻易的狗带)。
    4.2.1 获取预支付Id ,将所需要参数封装成字典

    NSMutableDictionary *orderParas = [NSMutableDictionary dictionary];
    
    [orderParas setObject: ZQAppID           forKey:@"appid"];       //开放平台appid
    [orderParas setObject: ZQMchID           forKey:@"mch_id"];//商户号
    [orderParas setObject: @"APP-001"        forKey:@"device_info"]; //支付设备号或门店号
    [orderParas setObject: noncestr          forKey:@"nonce_str"];   //随机串
    [orderParas setObject: @"APP"            forKey:@"trade_type"];  //支付类型,固定为APP
    [orderParas setObject: order_name        forKey:@"body"];        //订单描述,展示给用户
    [orderParas setObject: ZQPayNotifyURL    forKey:@"notify_url"];  //支付结果异步通知
    [orderParas setObject: tradeNo           forKey:@"out_trade_no"];//商户订单号
    [orderParas setObject: [ZQDeVice deviceIPAdress]    forKey:@"spbill_create_ip"];//发起支付的机器ip
    [orderParas setObject: order_price       forKey:@"total_fee"];       //订单金额,单位为分
    [orderParas setObject:attach forKey:@"attach"];//订单详细描述
    

    4.2.2添加sign加密串 形成XMl格式字符串 paras 为封装的字典(第一次加密)

    NSString *sign;
    NSMutableString *reqPars = [NSMutableString string];
    
    //生成xml的package
    NSArray *keys = [paras allKeys];
    [reqPars appendString:@"<xml>\\n"];
    
    for (NSString *categoryId in keys) {
        [reqPars appendFormat:@"<%@>%@</%@>\\n", categoryId, [paras objectForKey:categoryId],categoryId];
    }
    
    //生成签名,并将签名添加到签名包中
    sign = [self createMd5Sign:paras];
    [reqPars appendFormat:@"<sign>%@</sign>\\n</xml>", sign];
    
    return [NSString stringWithString:reqPars];
    

    4.2.3将获取的xml串传给微信获取预支付ID 接口地址 @"https://api.mch.weixin.qq.com/pay/unifiedorder" send为XML串

    //发送请求post xml数据
    NSData *res = [ZQUtil httpSend:ZQPrePayURL method:@"POST" data:send];
    
    ZQXMLHelper *xml  = [[ZQXMLHelper alloc] init];
    //开始解析
    [xml startParse:res];
    NSMutableDictionary *resParams = [xml getDict];
    
    //判断返回
    NSString *return_code = [resParams objectForKey:@"return_code"];
    NSString *result_code = [resParams objectForKey:@"result_code"];
     NSString *codeDes = [resParams objectForKey:@"err_code_des"];
    if ( [return_code isEqualToString:@"SUCCESS"] )
    {
        //生成返回数据的签名
        NSString *sign      = [self createMd5Sign:resParams];
        
        NSString *send_sign =[resParams objectForKey:@"sign"] ;
        
        //验证签名正确性
        if( [sign isEqualToString:send_sign]){
            if( [result_code isEqualToString:@"SUCCESS"]) {
                //验证业务处理状态
                prepayid    = [resParams objectForKey:@"prepay_id"];
                return_code = 0;
            }
        }
    }
    [dic setValue:prepayid forKey:@"prepay_id"];
    [dic setValue:codeDes forKey:@"err_code_des"];
    return dic;
    

    4.2.4 将获取的预支付id重新加密获取新的sign 封装成字典

    //获取到prepayid后进行第二次签名
    NSString    *package, *time_stamp, *nonce_str;
    
    //设置支付参数
    time_t now;
    
    time(&now);
    
    time_stamp  = [NSString stringWithFormat:@"%ld", now];
    nonce_str   = [ZQUtil stringMd5WithString:time_stamp];
    
    
    package         = @"Sign=WXPay";
    
    // 第二次签名参数列表
    NSMutableDictionary *signParas = [NSMutableDictionary dictionary];
    [signParas setObject: ZQAppID        forKey:@"appid"];
    [signParas setObject: nonce_str    forKey:@"noncestr"];
    [signParas setObject: package      forKey:@"package"];
    [signParas setObject: ZQMchID        forKey:@"partnerid"];
    [signParas setObject: time_stamp   forKey:@"timestamp"];
    [signParas setObject: prepayID     forKey:@"prepayid"];
    // 生成签名
    NSString *sign  = [self createMd5Sign:signParas];
    
    // 添加签名
    [signParas setObject: sign         forKey:@"sign"]; 
    

    时间戳为新的时间戳 随机数是通过时间戳MD5加密获取的

    4.2.5 至此加密结束 发起微信支付跳转到微信进行付款

    PayReq* req             = [[PayReq alloc] init];
    req.openID              = [paras objectForKey:@"appid"];
    req.partnerId           = [paras objectForKey:@"partnerid"];
    req.prepayId            = [paras objectForKey:@"prepayid"];
    req.nonceStr            = [paras objectForKey:@"noncestr"];
    req.timeStamp           = [[paras objectForKey:@"timestamp"] intValue];
    req.package             = [paras objectForKey:@"package"];
    req.sign                = [paras objectForKey:@"sign"];
    
    // 发起微信支付
    [WXApi sendReq:req];
    

    5.微信支付成功以后 要通知服务端以及APP端 服务器是通过回调地址进行操作,而对于App端通过Appdelegate中回调函数调用微信代理 步骤2中有说明。我就不再说了么么哒 (算了,我再这里在重新哔哔一次吧)
    //支付回调
    - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    return [WXApi handleOpenURL:url delegate:self];
    }
    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [WXApi handleOpenURL:url delegate:self];
    }

       #pragma mark 微信回调的代理方法
     - (void)onResp:(BaseResp *)resp {
    if ([resp isKindOfClass:[PayResp class]]) {
        PayResp *response = (PayResp *)resp;
        NSString *message;
        switch (response.errCode) {
          case WXSuccess:
            {  message=@"支付成功";
                [[NSNotificationCenter defaultCenter] postNotificationName:APP_PAY_SUCCESS object:nil];
            }
                break;
            case WXErrCodeCommon:
             //普通错误类型
                message=@"支付错误";
                break;
            case WXErrCodeUserCancel:
               //用户点击取消并且返回
               message=@"您取消了交易";
                break;
            case WXErrCodeSentFail:
                //发送失败
               message=@"信息发送失败";
                break;
            case WXErrCodeAuthDeny:
               //授权失败
                message=@"授权失败";
                break;
            case WXErrCodeUnsupport:
              //微信不不支持
               message=@"您的微信版本过低";
                break;
            default:
                NSLog(@"failed");
                break;
        }
    
      }
    }
    

    支付成功以后通过通知告知用户支付情况
    5.1 支付界面接收成功通知告知用户(我这里是跳转到新的界面)

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appPaySuccess) name:APP_PAY_SUCCESS object:nil];
    

    5.2通知方法

    -(void)appPaySuccess{
    ZQPaySuccessVC *paySuccessVC=[[ZQPaySuccessVC alloc]init];
    [self.navigationController pushViewController:paySuccessVC animated:YES];
    }
    

    5.3移除通知(不移除会崩溃呦)

    -(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:APP_PAY_SUCCESS object:nil];
    }
    

    6.支付完成!
    欢迎小伙伴们给我补充,提意见 么么哒~~~

    点我 获取支付法宝
    附:宝宝好累啊 关注本宝宝吧~~

    89c40b46f21fbe09f9774dff6d600c338644adc4.jpg

    相关文章

      网友评论

      • 生活本无度:小伙子跟我养猴子吧
      • c4d958f40e51:第二次签名是客户端做的吗?该怎么做呢?
        三粒黑子球:@stop回忆 其实就是md 5加密,你下载我的那个压缩包看看里面有没有,我记得有的
        c4d958f40e51:求分享生成签名的方法
        三粒黑子球:@stop回忆 你看看4.2.4
      • smart_small:小伙子,你很有前途,跟我学养猪吧
      • a261e396966d:调起支付的所有参数都是后已经弄好了,安卓那边能支付成功,我iOS这边调起微信支付界面后一直弹出提示框“支付签名验证失败”,然后我把sign随便放一串字符串居然不报验证失败还可以支付成功,后来我发现我调起支付时间戳的那个参数,我发送的跟微信接收到的是不一样,真的好奇怪,我换了旧版本的sdk也是这样????
        a261e396966d:@三粒黑子球 发现原因了,后台返回的时间戳是12位,微信这边是10位。但是我很奇怪sign随便放的话居然能够支付成功。
        三粒黑子球:@Dum 后台加密估计不对预支付id出现问题应该
      • 0ef0376dc7d1:楼主,网络访问异步请求怎么做啊?
        三粒黑子球: @0ef0376dc7d1 支付加密最好在服务器完成,尽量不要出现商户号等用户信息在APP里面,这样比较安全
        0ef0376dc7d1:@三粒黑子球 楼主说的好深奥,这个支付是在APP里面放的吧?
        三粒黑子球: @0ef0376dc7d1 其实是有一个异步回调地址,写在了字典中了,把这个一点转成xml格式的进行获取预支付id,这个过程中就把异步回调地址传过去了。支付完成以后微信一边想客户端通知,一边向服务器通知啊
      • 顺其自然JX:大神,我想问一下,客户端向服务器发送商品数据,和服务器签名后把信息返回给客服的是点击微信支付完成的吗?
        顺其自然JX:@三粒黑子球 明白了,谢了哈
        三粒黑子球:@顺其自然jx 是点击支付按钮的时候,这个时候在按钮方法中,与服务器通信,成功获得返回的预支付id再和微信进行通讯
      • Raybon_lee:那个点击左上角返回没回掉的原因是通过设置url么
        三粒黑子球: @Raybon_lee 我没有懂你的问题=_=
        Raybon_lee:@三粒黑子球 不应该呀,右侧都是点击从微信回掉正常的撒,:smile:
        三粒黑子球: @Raybon_lee 嗯呐对的,你可能设置的urlscheme不正确应该
      • jackiehoo:写的不错,态度很认真,表达也很清晰
      • 徐佳斌:果断关注
        三粒黑子球:@徐佳斌 谢谢支持呢🤗希望共同进步~
      • 我就是马选之人:支持~
        三粒黑子球:@敌羞吾去脱他衣 么么哒~🙄🙄
      • 拿铁加冰:小伙子你很不错
        三粒黑子球:@斜阳丶南欣 我会继续加油的~
      • 5dcb4835a39d:支持,谢谢
        三粒黑子球:@诸葛微笑 嗯呐嗯呐,希望共同进步呢
      • 暖火儿火儿:很给力
        三粒黑子球:@单单这样 还有很多不足的地方希望共同成长~:sunglasses:
      • 酷酷的哀殿:手机端发送这些数据,容易出问题吧
        NSDictionary *parameters =@{@"fcode": @"账号",
        @"password": @"密码",@"out_trade_no":@"订单号",@"total_fee":@"金额(分为单位)",@"attach":@"商品详情"};
        三粒黑子球:@酷酷的哀殿 嗯呐嗯呐,知道了,受教了呢~谢谢:yum:
        酷酷的哀殿:@三粒黑子球 如果已经有了订单号,只需要发送订单号即可。如果没有订单号,发送商品id以及购买的商品数量或样式等信息。
        金额和商品详情不建议手机端回传。两个原因:一个是可能被攻击,修改价格等信息;另一个是信息可能已经过时,比如价格发生变化。
        三粒黑子球:@酷酷的哀殿 这是网络请求,这这都是参数啊:fearful:
      • 8261d1cb4611:小伙子,你很有前途,跟我学养猪吧
      • 国民希大大:小伙子,不错不错

      本文标题:我的天呐🙈,怎么会有这么详细的微信支付说明

      本文链接:https://www.haomeiwen.com/subject/gtxmlttx.html