美文网首页iOSTools
ios 微信支付

ios 微信支付

作者: elite_kai | 来源:发表于2017-01-16 18:02 被阅读64次

    关于微信支付,我就忍不住要吐槽两句,因为项目中要用到微信支付,所以就从官方下载了微信支付的demo,自我感觉微信支付的demo和官方文档写的挺让人回味的,因为你看了以后吃饭的时候也会忍不住骂上两句。

    好了,废话不多说,接下来我们直接上代码
    在appdelegate中代码如下

    #import "AppDelegate.h"
    
    //微信支付
    #import "WXApi.h"
    
    @interface AppDelegate ()<WXApiDelegate>
    
    @end
    
    @implementation AppDelegate
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        
        //注册微信支付
        [WXApi registerApp:APP_id withDescription:@"demo"];
        
        return YES;
    }
    
    //iOS9 之后使用这个回调方法。
    - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
    {
        if ([url.host isEqualToString:@"pay"]) {
            
            return [WXApi handleOpenURL:url delegate:self];
        }
        
        return YES;
    }
    
    
    #pragma mark - 微信支付的代理方法
    - (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
    {
    
        if ([url.host isEqualToString:@"pay"]) {
            
            return [WXApi handleOpenURL:url delegate:self];
        }
        
        return YES;
        
    }
    
    #pragma mark - 微信支付成功的回调函数(这个方法必须写在delegate.m文件中)
    -(void)onResp:(BaseResp*)resp
    {
        if ([resp isKindOfClass:[PayResp class]]){
            
            PayResp *response = (PayResp*)resp;
            
            switch(response.errCode){
                    
                case WXSuccess:
                    //服务器端查询支付通知或查询API返回的结果再提示成功
                    //NSLog(@"支付成功");
                    
                    //发送通知给带有微信支付功能的视图控制器,告诉他支付成功了,请求后台订单状态,如果后台返回的订单也是成功的状态,那么可以进行下一步操作
                    [[NSNotificationCenter defaultCenter] postNotificationName:WEIXINPAYSUCCESSED object:nil userInfo:nil];
                    
                    
                    break;
                    
                default:
                    
                    /*
                     
                     resp.errCode = 2 用户取消支付
                     resp.errCode = -1 错误
                     */
                    NSLog(@"支付失败,retcode=%d ---- %@",resp.errCode,resp.errStr);
                    
                    break;
            }
        }
    }//微信支付成功的回调方法(回调函数)
    
    

    上面有两个系统回调的方法,第一个是针对ios9.0以后,第二个是针对ios9.0之前的
    在带有微信支付的页面我们做如下处理

    #import "ViewController.h"
    //微信支付
    #import "WXApi.h"
    #import "payRequsestHandler.h"
    #import "WXUtil.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(60, 100, 180, 100)];
        button.backgroundColor = [UIColor redColor];
        [button setTitle:@"微信支付" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(test) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
        
        //接受成功的通知
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(succeed) name:WEIXINPAYSUCCESSED object:nil];
    }
    
    #pragma mark - ASction Methods
    - (void)test
    {
        
        payRequsestHandler *handle = [[payRequsestHandler alloc]init];
        
        if ( [handle  init:APP_id mch_id:MCH_id]) {
            
            NSLog(@"初始化成功");
            
        }
        
        //设置商户密钥
        [handle setKey:PARTNER_id];
        
        //提交预支付,获得prepape_id
        NSString *order_name = @"测试";   //订单标题
        NSString *order_price = @"1";//测试价格 分为单位
        NSString *nocify_URL = nocify_url;    //回调借口
        NSString *noncestr  = [NSString stringWithFormat:@"%d", rand()]; //随机串
        NSString *orderno   = [NSString stringWithFormat:@"%ld",time(0)];
        NSMutableDictionary *params = [@{@"appid":APP_id,
                                         @"mch_id":MCH_id,
                                         @"device_info":[[[UIDevice currentDevice] identifierForVendor] UUIDString],
                                         @"nonce_str":noncestr,
                                         @"trade_type":@"APP",
                                         @"body":order_name,
                                         @"notify_url":nocify_URL,
                                         @"out_trade_no":orderno,//商户订单号:这个必须用后台的订单号
                                         @"spbill_create_ip":@"8.8.8.8",
                                         @"total_fee":order_price}mutableCopy];
        
        //提交预支付两次签名得到预支付订单的id(每次的请求得到的预支付订单id都不同)
        NSString *prepate_id = [handle sendPrepay:params];
        
        //提交预订单成功
        if (prepate_id != nil) {
            
            PayReq *request = [[PayReq alloc]init];
            
            //商家id
            request.partnerId = MCH_id;
            
            //订单id
            request.prepayId = prepate_id;
            
            //扩展字段(官方文档:暂时填写固定值)
            request.package = @"Sign=WXPay";
            
            //随机字符串
            request.nonceStr = noncestr;
            
            //时间戳
            request.timeStamp = (UInt32)[[NSDate date] timeIntervalSince1970];
            
            //sign参数(很经常出现的问题:就是调起支付到微信那边只出现一个确定按钮,单击确认按钮直接返回到app,出现这个问题100%是sign参数的问题)
            /*
             参数依次是: appid_key、partnerid_key、prepayid_key、固定值Sign=WXPay、预支付的随机数(跟上面得到预支付订单的随机数要一致)、支付时间(秒)
             
             */
            request.sign = [self createMD5SingForPay:APP_id partnerid:MCH_id prepayid:prepate_id package:@"Sign=WXPay" noncestr:noncestr timestamp:(UInt32)[[NSDate date] timeIntervalSince1970]];
            
            
            
            //带起微信支付
            if ([WXApi sendReq:request]) {
                
                
                // NSLog(@"走这里啊");
                
            }else{
                
                //NSLog(@"走之类");
                //未安装微信客户端
    //            [[[UIAlertView alloc]initWithTitle:@"测试demo" message:@"您还未安装微信客户端,请前往Appstore下载或者选择其他支付方式!" delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]show];
                
            }
            
        }
        
    }//点击微信支付
    
    
    #pragma mark - Private Methods
    -(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",(unsigned int)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 *result = [self md5:contentString];
        return result;
        
    }//创建发起支付时的sige签名
    
    
    -(NSString *)md5:(NSString *)str
    {
        const char *cStr = [str UTF8String];
        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]
                ];
    }//MD5 加密
    
    
    - (void)succeed
    {
        
        NSLog(@"支付成功");
        
        
    }//支付成功的监听方法
    
    
    #pragma mark - OverRide Methods
    - (void)dealloc
    {
        
        [[NSNotificationCenter defaultCenter] removeObserver:self name:WEIXINPAYSUCCESSED object:nil];
        
        
    }//移除通知
    
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    
    

    这里面有几个名字我给大家解释一下,PARTNER_id是从商户中心那里获取的,当你在微信开放平台创建的应用申请微信支付成功以后,进入到商户中心那里自己设置一个32位的字符串。MCH_id是商家的id,也就是商户号。

    APP_id是在微信开放平台创建应用的appid。notify_url是回调接口,也就是一个url链接,是由服务器给你的

    最后还有一点,大家通常会遇到一个问题,在调起微信以后,发现只有一个空白的页面,中间有一个确定的按钮,这种情况是sign签名的问题

    下面附上微信支付的demo,里面的一些相关信息需要换成自己开放平台中自己应用的信息
    https://github.com/EngineerLXK/WeiXinPay

    相关文章

      网友评论

        本文标题:ios 微信支付

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