今天给大家说说这个微信支付。当时我写这个的时候的确感觉挺坑的。文档不全不说,还给介绍的不详细,简直是醉了,好了,废话少说 直接上代码。
在这之前,先添加下微信的依赖库
SystemConfiguration.framework libz.tbd libsqlite3.0.tbd libc++.tbd
CoreTelephony.framework(这个库官方文档没说,这就是一个坑,没它还不能行)
把微信的SDK放入项目中
在AppDelegate 中算是注册微信把
[WXApiregisterApp:@"appid"]; //appid 是你在微信官方申请的ID 当你申请成功之后就会有了
然后在你需要的地方 拉起微信支付
//调起微信支付
PayReq* req = [[PayReqalloc] init];
req.openID =APP_ID;//你申请的ID
req.partnerId =MCH_ID;//商户ID
req.prepayId = prepayId;//预支付订单 (下面会详细介绍)
req.nonceStr = nonce_str;//随机串 防止订单重复
req.timeStamp = time_stamp.intValue;//时间戳 同样防止订单重复
req.package = @"Sign=WXPay"//固定死值 (目前是死的 不知道以后微信会不会换)
req.sign = sign;//二次签名 (下面会详细介绍)
先说一下预支付订单
什么为预支付订单,根据官方的解释是你自己先在微信官网生成一个支付订单,
//================================
//预付单参数订单设置
//================================
srand( (unsigned)time(0) );
NSString *noncestr = [NSStringstringWithFormat:@"%d",rand()];
NSLog(@"%@",noncestr);
NSString *orderno = [NSStringstringWithFormat:@"%ld",time(0)];
NSMutableDictionary *packageParams = [NSMutableDictionarydictionary];
[packageParams setObject:APP_ID forKey:@"appid"]; //开放平台appid
[packageParams setObject:MCH_ID forKey:@"mch_id"]; //商户号
// [packageParams setObject: @"013467007045764" forKey:@"device_info"]; //支付设备号或门店号
[packageParams setObject:@"1add1a30ac87aa2db52f57a2375d8fec" forKey:@"nonce_str"]; //随机串
[packageParams setObject:@"APP" forKey:@"trade_type"]; //支付类型,固定为APP
[packageParams setObject: order_name forKey:@"body"]; //订单描述,展示给用户
[packageParams setObject:@"http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php" forKey:@"notify_url"]; //支付结果异步通知
[packageParams setObject:@"1415659991" forKey:@"out_trade_no"];//商户订单号
[packageParams setObject: @"255.255.255.255" forKey:@"spbill_create_ip"];//发器支付的机器ip
[packageParams setObject: order_price forKey:@"total_fee"]; //订单金额,单位为分
[packageParams setObject:@"333" forKey:@"attach"];
上面这是预支付订单你需要填写的基础参数 这是一个字典 然后把这些参数进行签名 MD5加密 XML解析 等等
把上面的字典 传入下面
//提交预支付
-(NSString *)sendPrepay:(NSMutableDictionary *)prePayParams
{
NSString *prepayid =nil;
//获取提交支付
NSString *send = [selfgenPackage:prePayParams]; //这个地方是XML解析
NSLog(@"%@",send);
payUrl =@"https://api.mch.weixin.qq.com/pay/unifiedorder"; //这是支付统一网址
//发送请求post xml数据
NSData *res = [selfhttpSend:payUrlmethod:@"POST"data:send];
NSLog(@"%@",res); //在这个地方打印你的XML解析是否有问题 下面我给了XML解析
NSLog(@"%@",[[NSStringalloc] initWithData:resencoding:NSUTF8StringEncoding]); //转NSUTF8StringEncoding
//开始解析
[self startParse:res];
NSMutableDictionary *resParams = [xmlgetDict];
NSLog(@"%@",resParams);
//判断返回
NSString *return_code = [resParamsobjectForKey:@"return_code"];
NSString *result_code = [resParamsobjectForKey:@"result_code"];
if ( [return_codeisEqualToString:@"SUCCESS"] )
{
//生成返回数据的签名
NSString *sign = [selfcreateMd5Sign:resParams ];
NSString *send_sign =[resParamsobjectForKey:@"sign"] ;
//验证签名正确性
if( [signisEqualToString:send_sign]){
if( [result_codeisEqualToString:@"SUCCESS"]) {
//验证业务处理状态
prepayid = [resParams objectForKey:@"prepay_id"];
return_code = 0;
}
}else{
last_errcode =1;
}
}else{
last_errcode =2;
}
//在这个地方成功 恭喜你 你的第一步 预支付订单已经出来了
return prepayid;
}
//获取package带参数的签名包 拼接XML
-(NSString *)genPackage:(NSMutableDictionary*)packageParams
{
NSString *sign;
NSMutableString *reqPars=[NSMutableStringstring];
//生成签名
sign = [selfcreateMd5Sign:packageParams];
//生成xml的package
NSArray *keys = [packageParamsallKeys];
[reqPars appendString:@"<xml>\n"];
for (NSString *categoryIdin keys) {
[reqPars appendFormat:@"<%@>%@</%@>\n", categoryId, [packageParamsobjectForKey:categoryId],categoryId];
}
[reqPars appendFormat:@"<sign>%@</sign>\n</xml>", sign];
return [NSStringstringWithString:reqPars];
}
//package 参数
-(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:@""]
&& ![categoryId isEqualToString:@"sign"]
&& ![categoryId isEqualToString:@"key"]
)
{
[contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]];
}
}
//添加key字段
NSLog(@"%@",spkey);
[contentString appendFormat:@"key=%@", spkey];
//得到MD5 sign签名
NSString *md5Sign =[self md5:contentString];
//输出Debug Info
[debugInfo appendFormat:@"MD5签名字符串:\n%@\n\n",contentString];
return md5Sign;
}
//MD5加密
-(NSString *) md5:(NSString *)str
{
constchar *cStr = [str UTF8String];
unsignedchar digest[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, (unsignedint)strlen(cStr), digest );
NSMutableString *output = [NSMutableStringstringWithCapacity:CC_MD5_DIGEST_LENGTH *2];
for(int i =0; i < CC_MD5_DIGEST_LENGTH; i++)
[output appendFormat:@"%02X", digest[i]];
return output;
}
//http 请求
-(NSData *) httpSend:(NSString *)url method:(NSString *)method data:(NSString *)data
{
NSMutableURLRequest *request = [[NSMutableURLRequestalloc] initWithURL:[NSURLURLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalCacheDatatimeoutInterval:5];
//设置提交方式
[request setHTTPMethod:method];
//设置数据类型
[request addValue:@"text/xml"forHTTPHeaderField:@"Content-Type"];
//设置编码
[request setValue:@"UTF-8"forHTTPHeaderField:@"charset"];
//如果是POST
[request setHTTPBody:[datadataUsingEncoding:NSUTF8StringEncoding]];
NSError *error;
//将请求的url数据放到NSData对象中
NSData *response = [NSURLConnectionsendSynchronousRequest:request returningResponse:nilerror:&error];
return response;
//return [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
}
//解析XML
-(void) startParse:(NSData *)data{
dictionary =[NSMutableDictionarydictionary];
contentString=[NSMutableStringstring];
xmlElements = [[NSMutableArrayalloc] init];
xmlParser = [[NSXMLParseralloc] initWithData:data];
[xmlParsersetDelegate:self];
[xmlParserparse];
}
============================================上面的就是你第一步需要做的事==========================================
如果下面的步骤你都成功了 恭喜 离成功就不远了 接下来进行第二次签名 也就是验证签名
//这个地方的prePayid 是你的预支付订单号 就是上面成功之后会出来一个订单号
if ( prePayid != nil) {
//获取到prepayid后进行第二次签名
NSString *package, *time_stamp, *nonce_str;
//设置支付参数
time_t now;
time(&now);
time_stamp = [NSStringstringWithFormat:@"%ld", now];
nonce_str = [WXUtilmd5:time_stamp];
//重新按提交格式组包,微信客户端暂只支持package=Sign=WXPay格式,须考虑升级后支持携带package具体参数的情况
//package = [NSString stringWithFormat:@"Sign=%@",package];
package = @"Sign=WXPay";
//第二次签名参数列表
NSMutableDictionary *signParams = [NSMutableDictionarydictionary];
[signParams setObject:APP_ID forKey:@"appid"];
[signParams setObject: nonce_str forKey:@"noncestr"];
[signParams setObject: package forKey:@"package"];
[signParams setObject:MCH_ID forKey:@"partnerid"];
[signParams setObject: time_stamp forKey:@"timestamp"];
[signParams setObject: prePayid forKey:@"prepayid"];
//[signParams setObject: @"MD5" forKey:@"signType"];
//生成签名
NSString *sign = [self createMd5Sign:signParams]; //上面的package 参数
//添加签名
[signParams setObject: sign forKey:@"sign"];
NSLog(@"%@",sign);//这个地方出来的就是sign 二次验证的签名
//返回参数列表
return ;
}else{
//获取订单号失败
}
恭喜你到了这个地方说明上面的参数都对了 你就可以返回最上面我写的 拉起微信支付 把刚才拼出来的东西对应的填写进去,你就可以进行微信支付了
小弟写的比较陋 如果发现什么不妥之处 请告诉我。