微信支付哪些事
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型.
暂时只发现这两个.
将来的自己,会感谢现在不放弃的自己!