微信支付哪些事

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型.

暂时只发现这两个.

 

posted @ 2016-06-29 09:41  TheYouth  阅读(1111)  评论(0编辑  收藏  举报