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型.
暂时只发现这两个.