zoukankan      html  css  js  c++  java
  • 微信支付哪些事

    1.根据官方文档,先将所用的库加入工程里去如sdk1.6.2中需要的库如下(具体请参照官方呆萌(demo)):

    libxml2.tbd libc++.tbd libsqlite3.0.tbd CoreTelephony.framework libstdc++.6.0.9.tbd libz.tbd

    2.将微信加入白名单中 TARGETS -> Info ->LSApplicationQueriesSchemes ->weixin ,weichat.

    3.加入微信回调地址(在微信公共平台下创建应用得到的appid),TAGETS->Info ->URL Types

    4.在AppDelegate导入头文件,这里我创建了一个微信管理类 

    #import "WXApiManager.h" //这类里面包含了官门呆萌中提供的类 #import "WXApi.h"   #import "WXApiObject.h"

    /**注册微信appid*/
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
    
        //向微信注册 wxc43f9b2120a05409
        [WXApi registerApp:APP_ID withDescription:@"weixin"];
        
        return YES;
    }
    //打开微信
    //微信
    - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
        return  [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
    }
    
    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
        NSLog(@"%@",url);
        return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
    }

    5.发送第一次签名(支付页面)

     if ([WXApi isWXAppInstalled]) {
                //  随机生机字符串
                NSString *noncestr = [self generateTradeNO];
                NSLog(@"%@",noncestr);
                
                
                //随机生成的商品订单号
                NSString *out_trade_no = [self getOrderNumber];
                
                //--------modey,1分钱
                NSString *total_fee = @"1"; 
                //--------create_ip,请看下面的,getIPhoneIp类
                NSString *creteIp = [getIPhoneIP getIPAddress];
                NSString *tradeType = @"APP";
                
                //获取sign签名,关于签名参数,请看官门文档中要拼接的参数,请参照下面的MD5类
                DataMD5 *data = [[DataMD5 alloc] initWithAppid:APP_ID mch_id:MCH_ID nonce_str:noncestr partner_id:PARTNER_ID body:@"hotel" out_trade_no:out_trade_no total_fee:total_fee spbill_create_ip:creteIp notify_url:@"http://www.weixin.qq.com/wxpay/pay.php" trade_type:tradeType];
                NSString  *sign = [data getSignForMD5];
                
                NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                [dic setValue:@"appid" forKey:@"appid"];//公众账号ID,创建商户自己获取的
                [dic setValue:@"商户号" forKey:@"mch_id"];//商户号
                [dic setValue:noncestr forKey:@"nonce_str"];//随机字符串
                [dic setValue:sign forKey:@"sign"];//签名
                [dic setValue:@"hotel" forKey:@"body"];//商品描述
                [dic setValue:out_trade_no forKey:@"out_trade_no"];//订单号
                [dic setValue:total_fee forKey:@"total_fee"];//金额
                [dic setValue:creteIp forKey:@"spbill_create_ip"];//终端IP
                [dic setValue:@"http://www.weixin.qq.com/wxpay/pay.php" forKey:@"notify_url"];//通知地址
                [dic setValue:tradeType forKey:@"trade_type"];//交易类型
                // 转换成xml字符串
                NSString *string = [dic XMLString];
                //转换成xml
                [self http:string];
            }else{
                
                [MBProgressHUD showError:@"未安装微信"];
            }

    6.发送二次签名,(支付页面)

    - (void)http:(NSString *)xml{
    
     
    
        [MBProgressHUD showMessage:@"正在获取支付订单..."];
    
        AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    
        //这里传入的xml字符串只是形似xml,但是不是正确是xml格式,需要使用af方法进行转义
    
        manager.responseSerializer = [[AFHTTPResponseSerializer alloc] init];
    
        [manager.requestSerializer setValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    
        [manager.requestSerializer setValue:@"https://api.mch.weixin.qq.com/pay/unifiedorder" forHTTPHeaderField:@"SOAPAction"];
    
        [manager.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) {
    
            return xml;
     //真正的xml
        }];
    
        //发起请求
    
        [manager POST:@"https://api.mch.weixin.qq.com/pay/unifiedorder" parameters:xml success:^(AFHTTPRequestOperation *operation, id responseObject) {
    
            NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] ;
    
            KGNSLog(@"%@",xml);
    
            //将微信返回的xml数据解析转义成字典,注意这里需要改XMLDictionary 第三方库
    
            NSDictionary *dic = [NSDictionary dictionaryWithXMLString:responseString];
    
            //判断返回的许可
    
            if ([[dic objectForKey:@"result_code"] isEqualToString:@"SUCCESS"] &&[[dic objectForKey:@"return_code"] isEqualToString:@"SUCCESS"] ) {
    
                //发起微信支付,设置参数
    
                PayReq *request = [[PayReq alloc] init];
    
                request.openID = [dic objectForKey:@"appid"];
    
                request.partnerId = [dic objectForKey:@"mch_id"];
    
                request.prepayId= [dic objectForKey:@"prepay_id"];
    
                request.package = @"Sign=WXPay";
    
                request.nonceStr = [dic objectForKey:@"nonce_str"];
    
    //            request.nonceStr= noncestr;
    
           
    
                KGNSLog(@"%@",request.nonceStr);
    
                //将当前事件转化成时间戳
    
                NSDate *datenow = [NSDate date];
    
                NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
    
                UInt32 timeStamp =[timeSp intValue];
    
                request.timeStamp= timeStamp;
    
                // 签名加密,二次签名
    
                DataMD5 *md5 = [[DataMD5 alloc] init];
    
                request.sign=[md5 createMD5SingForPay:request.openID partnerid:request.partnerId prepayid:request.prepayId package:request.package noncestr:request.nonceStr timestamp:request.timeStamp];
    
                // 调用微信
    
                [WXApi sendReq:request];
    
                [MBProgressHUD hideHUD];
    
            }else{
    
                KGNSLog(@"参数不正确,请检查参数");
    
                [MBProgressHUD hideHUD];
    
                [MBProgressHUD showError:@"支付错误!"];
    
            }
    
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    
            KGNSLog(@"error is %@",error);
    
            [MBProgressHUD hideHUD];
    
            [MBProgressHUD showError:@"未完成支付"];
    
        }];
    
    }

    7.微信管理单例类继承<WXApiDelegate>用来实现回调的方法

    - (void)onResp:(BaseResp *)resp {
        
        //支付返回结果,实际支付结果需要去微信服务器端查询
        NSString *strMsg = [NSString stringWithFormat:@"errcode:%d",resp.errCode];
        NSString *strTitle;
        
        if ([resp isKindOfClass:[SendMessageToWXResp class]]) {
            strTitle = [NSString stringWithFormat:@"发送媒体消息结果"];
        }
        
      if([resp isKindOfClass:[PayResp class]]){
          //支付返回结果,实际支付结果需要去微信服务站查询
          strTitle = [NSString stringWithFormat:@"支付结果"];
            switch (resp.errCode) {
                case WXSuccess:{
                    strMsg = @"支付结果:成功!";
                    NSLog(@"支付成功-PaySuccess,retcode = %d", resp.errCode);
                    //这里应用发送通知,来清楚支付的结果
                    NSNotification *notification = [NSNotification notificationWithName:ORDER_PAY_NOTIFICATION object:@"success"];
                    [[NSNotificationCenter defaultCenter] postNotification:notification];
                    
                    break;
                }
                default:{
                    strMsg = [NSString stringWithFormat:@"支付结果:失败!retcode = %d, retstr = %@", resp.errCode,resp.errStr];
                    NSLog(@"错误,retcode = %d, retstr = %@", resp.errCode,resp.errStr);
                    
                    NSNotification *notification = [NSNotification notificationWithName:ORDER_PAY_NOTIFICATION object:@"fail"];
                    [[NSNotificationCenter defaultCenter] postNotification:notification];
                    break;
                }
            }
    //        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:strTitle message:strMsg delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    //        [alert show];
          
        }
        
    }

    8.在(支付页面监听通知,并实现通知方法,告诉用户支付的结果)

    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        if ([WXApi isWXAppInstalled]) {
            
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getOrderPayResult:) name:ORDER_PAY_NOTIFICATION object:nil];
            
        }
    }
    //微信 pay Result
    - (void)getOrderPayResult:(NSNotification *)noti{
    
        if ([noti.object isEqualToString:@"success"])
        {
            [self alert:@"恭喜" msg:@"您已成功支付啦!"];
        }
        else
        {
            [self alert:@"提示" msg:@"支付失败"];
            
        }
    }

    9.支付页面的一些方法

    1.随机生机字符串
    
    - (NSString *)generateTradeNO
    {
        static int kNumber = 15;
        
        NSString *sourceStr = @"0123456789ABCDEFGHIJKLMNOPQRST";
        NSMutableString *resultStr = [[NSMutableString alloc] init];
        srand(time(0));
        for (int i = 0; i < kNumber; i++)
        {
            unsigned index = rand() % [sourceStr length];
            NSString *oneStr = [sourceStr substringWithRange:NSMakeRange(index, 1)];
            [resultStr appendString:oneStr];
        }
        return resultStr;
    }
    2.//随机生成的商品订单号
    - (NSString *)getOrderNumber{
        int random = arc4random()%10000;
        return [KCommon md5:[NSString stringWithFormat:@"%d",random]];
    }
    3.获取当前ip
    +(NSString *)getIPAddress {
        NSString *address = @"error";
        struct ifaddrs *interfaces = NULL;
        struct ifaddrs *temp_addr = NULL;
        int success = 0;
        // retrieve the current interfaces - returns 0 on success
        success = getifaddrs(&interfaces);
        if (success == 0) {
            // Loop through linked list of interfaces
            temp_addr = interfaces;
            while(temp_addr != NULL) {
                if(temp_addr->ifa_addr->sa_family == AF_INET) {
                    // Check if interface is en0 which is the wifi connection on the iPhone
                    if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
                        // Get NSString from C String
                        address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
                    }
                }
                temp_addr = temp_addr->ifa_next;
            }
        }
        // Free memory
        freeifaddrs(interfaces);
        return address;
    }

    4.MD5类,注意下面代码添加商户密钥key字段[contentString appendFormat:@"key=%@",PARTNER_ID],这里需要填商户密钥

    -(instancetype)initWithAppid:(NSString *)appid_key
                          mch_id:(NSString *)mch_id_key
                       nonce_str:(NSString *)noce_str_key
                      partner_id:(NSString *)partner_id
                            body:(NSString *)body_key
                   out_trade_no :(NSString *)out_trade_no_key
                       total_fee:(NSString *)total_fee_key
                spbill_create_ip:(NSString *)spbill_create_ip_key
                      notify_url:(NSString *)notify_url_key
                      trade_type:(NSString *)trade_type_key{
        self = [super init];
        if (self) {
            _appid = appid_key;
            _mch_id = mch_id_key;
            _nonce_str = noce_str_key;
            _partnerkey = partner_id;
            _body = body_key;
            _out_trade_no = out_trade_no_key;
            _total_fee = total_fee_key;
            _spbill_create_ip = spbill_create_ip_key;
            _notify_url = notify_url_key;
            _trade_type = trade_type_key;
            
        }
        return self;
    }
    ///获取sign签名
    - (NSString *)getSignForMD5{
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setValue:_appid forKey:@"appid"];
        [dic setValue:_mch_id forKey:@"mch_id"];
        [dic setValue:_nonce_str forKey:@"nonce_str"];
        [dic setValue:_body forKey:@"body"];
        [dic setValue:_out_trade_no forKey:@"out_trade_no"];
        [dic setValue:_total_fee forKey:@"total_fee"];
        [dic setValue:_spbill_create_ip forKey:@"spbill_create_ip"];
        [dic setValue:_notify_url forKey:@"notify_url"];
        [dic setValue:_trade_type forKey:@"trade_type"];
        return [self createMd5Sign:dic];
    }
    
    //创建签名
    -(NSString*) createMd5Sign:(NSMutableDictionary*)dict
    {
        NSMutableString *contentString  =[NSMutableString string];
        NSArray *keys = [dict allKeys];
        //按字母顺序排序
        NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
            return [obj1 compare:obj2 options:NSNumericSearch];
        }];
        //拼接字符串
        for (NSString *categoryId in sortedArray) {
            if (   ![[dict objectForKey:categoryId] isEqualToString:@""]
                && ![[dict objectForKey:categoryId] isEqualToString:@"sign"]
                && ![[dict objectForKey:categoryId] isEqualToString:@"key"]
                )
            {
                [contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]];
            }
        }
        //添加商户密钥key字段
        [contentString appendFormat:@"key=%@", _partnerkey];
        //得到MD5 sign签名
        NSString *md5Sign =[self md5:contentString];
        
        return md5Sign;
    }
    
    //创建发起支付时的sige签名
    -(NSString *)createMD5SingForPay:(NSString *)appid_key partnerid:(NSString *)partnerid_key prepayid:(NSString *)prepayid_key package:(NSString *)package_key noncestr:(NSString *)noncestr_key timestamp:(UInt32)timestamp_key{
        NSMutableDictionary *signParams = [NSMutableDictionary dictionary];
        [signParams setObject:appid_key forKey:@"appid"];
        [signParams setObject:noncestr_key forKey:@"noncestr"];
        [signParams setObject:package_key forKey:@"package"];
        [signParams setObject:partnerid_key forKey:@"partnerid"];
        [signParams setObject:prepayid_key forKey:@"prepayid"];
        [signParams setObject:[NSString stringWithFormat:@"%u",timestamp_key] forKey:@"timestamp"];
        
        NSMutableString *contentString  =[NSMutableString string];
        NSArray *keys = [signParams allKeys];
        //按字母顺序排序
        NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
            return [obj1 compare:obj2 options:NSNumericSearch];
        }];
        //拼接字符串
        for (NSString *categoryId in sortedArray) {
            if (   ![[signParams objectForKey:categoryId] isEqualToString:@""]
                && ![[signParams objectForKey:categoryId] isEqualToString:@"sign"]
                && ![[signParams objectForKey:categoryId] isEqualToString:@"key"]
                )
            {
                [contentString appendFormat:@"%@=%@&", categoryId, [signParams objectForKey:categoryId]];
            }
        }
        //添加商户密钥key字段
        [contentString appendFormat:@"key=%@",PARTNER_ID];
        //    NSString *signString =[self md5:contentString];
        NSString *result = [self md5:contentString];
        return result;
    }
    
    -(NSString *) md5:(NSString *)str
    {
        const char *cStr = [str UTF8String];
        //加密规则,因为逗比微信没有出微信支付demo,这里加密规则是参照安卓demo来得
        unsigned char result[16]= "0123456789abcdef";
        CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
        //这里的x是小写则产生的md5也是小写,x是大写则md5是大写,这里只能用大写,逗比微信的大小写验证很逗
        return [NSString stringWithFormat:
                @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                result[0], result[1], result[2], result[3],
                result[4], result[5], result[6], result[7],
                result[8], result[9], result[10], result[11],
                result[12], result[13], result[14], result[15]
                ];
    }

    10.微信支付那些坑

    1.如果你微信支付代码全写上了,跳转页面只出现了一个确定按钮,不要怀疑人生,请看看是不是密钥没有填,md5签名出现了问题.

    2.时间戳必须符合微信官方的规范,10位数,一定记得最后要转换成int或integer型.

    暂时只发现这两个.

    将来的自己,会感谢现在不放弃的自己!
  • 相关阅读:
    Linux日志文件/var/log详解
    QT 的信号与槽机制介绍
    利用线程通信,写2个线程,一个线程打印1~52,另一个线程打印A~Z,打印顺序应该使12A34B56C···5152Z
    mysql快速安装
    zabbix安装源
    mysql手动安装
    没有可用软件包 zabbixservermysql
    【转载】web 部署专题(一):Gunicorn运行与配置方法
    supervisor快速配置
    linux监控脚本状态失败后拉起
  • 原文地址:https://www.cnblogs.com/TheYouth/p/5625759.html
Copyright © 2011-2022 走看看