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

公司要求项目添加上微信支付和支付宝支付在这里我将自己的心得以及自己总结的步骤总结在这里,希望让读者少一点入坑。,那么我们现在从最难的骨头啃起来,一步步教大家完成微信支付,关于申请微信支付的东西我就不再这里累赘,很多帖子都有(其实是因为公司这部分我没有参与,嘿嘿)。开始我们的微信支付的旅行吧。
前提条件,让你的 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](http://upload-images.jianshu.io/upload_images/1141241-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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容