iOS 微信支付 SDK版本1.7.5(2016年12月27日)
来源:互联网 发布:linux的home目录 编辑:程序博客网 时间:2024/05/21 06:39
第一步: 导入微信SDK
第二步: 导入framework
第三步: 设置URL Types
第四步: 将微信加入跳转白名单(右键info.plist -> Open As -> Source Code)
<key>LSApplicationQueriesSchemes</key>
<array>
<string>wechat</string>
<string>weixin</string>
</array>
<array>
<string>wechat</string>
<string>weixin</string>
</array>
第五步: 在AppDelegate.m中引入包: #import"WXApi.h"
第六步: 注册微信: [WXApiregisterApp:WeChatAPPID]; (注: 如果使用友盟, 需要在微信注册之前注册)
注: 这步操作后运行, 如果是新建的项目可能会报这个错误
解决办法: 要在Build Settings -> Other Linker Flags 添加 -ObjC
第七步: 导入解析XML数据的类XMLReader
第八步: 创建一个PCH文件 Common.pch
定义三个宏
#define WeChatAppID @"xxxxxxxxxxxxx"// APPID
#define PartnerID @"xxxxx"//商户ID
#define APISignKey @"xxxxxxxx商户平台 -> 账户中心 -> API安全 -> API密钥, 设置密钥"// API私钥
第九步: ViewController.m中的代码#define PartnerID @"xxxxx"//商户ID
#define APISignKey @"xxxxxxxx商户平台 -> 账户中心 -> API安全 -> API密钥, 设置密钥"// API私钥
//// ViewController.m// ZHWeChatPay//// Created by 周昊 on 2016/12/28.// Copyright © 2016年 Cloud. All rights reserved.//#import "ViewController.h"#import "WXApi.h"#import <CommonCrypto/CommonDigest.h> // MD5加密需要导此包// ------------获取终端IP地址需要以下引入及定义#include <ifaddrs.h>#include <arpa/inet.h>#include <net/if.h>#define IOS_CELLULAR @"pdp_ip0"#define IOS_WIFI @"en0"#define IOS_VPN @"utun0"#define IP_ADDR_IPv4 @"ipv4"#define IP_ADDR_IPv6 @"ipv6"// -------------#import "XMLReader.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; UIButton *payServerBtn = [UIButton buttonWithType:UIButtonTypeSystem]; [payServerBtn setTitle:@"包括服务器端操作的支付" forState:UIControlStateNormal]; [payServerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [payServerBtn addTarget:self action:@selector(zh_weChatPayIncludeServer) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:payServerBtn]; [payServerBtn sizeToFit]; payServerBtn.frame = CGRectMake((self.view.frame.size.width - payServerBtn.frame.size.width) / 2.0, 200, payServerBtn.frame.size.width, payServerBtn.frame.size.height); UIButton *payBtn = [UIButton buttonWithType:UIButtonTypeSystem]; [payBtn setTitle:@"微信支付" forState:UIControlStateNormal]; [payBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [payBtn addTarget:self action:@selector(zh_weChatPay) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:payBtn]; [payBtn sizeToFit]; payBtn.frame = CGRectMake((self.view.frame.size.width - payBtn.frame.size.width) / 2.0, CGRectGetMaxY(payServerBtn.frame) + 100, payBtn.frame.size.width, payBtn.frame.size.height); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(zh_handleWeChatPayResult:) name:@"doWeChatPayResult" object:nil];}- (void)zh_handleWeChatPayResult:(NSNotification *)notification{ BaseResp *resp = notification.object; switch (resp.errCode) { case WXSuccess: NSLog(@"支付成功"); break; default: NSLog(@"支付失败"); break; }}#pragma mark - 微信支付(包括服务器端的操作)- (void)zh_weChatPayIncludeServer{ if (![WXApi isWXAppInstalled]) { NSLog(@"未安装微信客户端"); return; } if (![WXApi isWXAppSupportApi]) { NSLog(@"不支持微信支付"); return; } NSString *url = @"https://api.mch.weixin.qq.com/pay/unifiedorder"; // 请求腾讯服务器 // 拼接详细的订单数据 NSDictionary *postDict = [self zh_getProductArgs]; // 服务器端拼接数据及签名 // 拼接调用支付接口所需要的参数(拼接成XML格式) NSString *string = [NSString stringWithFormat:@"<xml><sign>%@</sign><appid>%@</appid><body>%@</body><mch_id>%@</mch_id><nonce_str>%@</nonce_str><notify_url>%@</notify_url><out_trade_no>%@</out_trade_no><spbill_create_ip>%@</spbill_create_ip><total_fee>%d</total_fee><trade_type>APP</trade_type></xml>",[postDict objectForKey:@"sign"], WeChatAppID, [postDict objectForKey:@"body"], PartnerID, [postDict objectForKey:@"nonce_str"], [postDict objectForKey:@"notify_url"], [postDict objectForKey:@"out_trade_no"], [postDict objectForKey:@"spbill_create_ip"],[[postDict objectForKey:@"total_fee"] intValue]]; // 创建网络请求 NSURL *requestURL = [NSURL URLWithString:url]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:requestURL]; [request setHTTPMethod:@"POST"]; [request setValue:@"application/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:[string dataUsingEncoding:NSUTF8StringEncoding]]; NSHTTPURLResponse* urlResponse = nil; NSError *error = [[NSError alloc] init]; NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error]; NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; if ([urlResponse statusCode] >= 200 && [urlResponse statusCode] < 300) { NSError *error2 = [NSError alloc]; // 从腾讯服务器请求回来的数据将XML格式解析成字典 NSDictionary *xmlDict = [[XMLReader dictionaryForXMLString:result error:&error2] objectForKey:@"xml"]; // 调用支付接口 PayReq *payRequest = [[PayReq alloc]init]; payRequest.partnerId = [[xmlDict objectForKey:@"mch_id"] objectForKey:@"text"]; payRequest.prepayId = [[xmlDict objectForKey:@"prepay_id"] objectForKey:@"text"]; payRequest.package = @"Sign=WXPay"; payRequest.nonceStr = [[xmlDict objectForKey:@"nonce_str"] objectForKey:@"text"]; payRequest.timeStamp = [[NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]] intValue]; // 构造参数列表,再次签名 NSMutableDictionary *payDict = [NSMutableDictionary dictionary]; [payDict setObject:WeChatAppID forKey:@"appid"]; [payDict setObject:payRequest.nonceStr forKey:@"noncestr"]; [payDict setObject:payRequest.package forKey:@"package"]; [payDict setObject:payRequest.partnerId forKey:@"partnerid"]; [payDict setObject:payRequest.prepayId forKey:@"prepayid"]; [payDict setObject:[NSString stringWithFormat:@"%u", (unsigned int)payRequest.timeStamp]forKey:@"timestamp"]; payRequest.sign = [self zh_genSign:payDict]; [WXApi sendReq:payRequest]; }}// 构造预付订单参数列表- (NSDictionary *)zh_getProductArgs{ NSMutableDictionary *params = [NSMutableDictionary dictionary]; NSString *timeStamp = [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]]; // 获取时间戳 NSString *nonceStr = [[self zh_md5:[NSString stringWithFormat:@"%d", arc4random() % 10000]] uppercaseString]; // 获取32位内的随机串, 防重发 // 获取商家对用户的唯一标识 NSString *outTradNo = [NSString stringWithFormat:@"%d", arc4random() % 10000]; NSString *out_trade_no= [NSString stringWithFormat:@"%@%@",timeStamp,outTradNo];//获取商户订单号 [params setObject:WeChatAppID forKey:@"appid"];//必填 [params setObject:nonceStr forKey:@"nonce_str"];//随机字符串,必填 [params setObject:@"APP" forKey:@"trade_type"]; //交易类型 必填 [params setObject:@"有逼格的程序员" forKey:@"body"];//商品描述,必填 [params setObject:@"这里是你本地接收回调通知的地址" forKey:@"notify_url"]; // 此处填可以让后台写个接口,如果支付成功,则微信后台调用此接口,返回yes,失败则返回no; [params setObject:out_trade_no forKey:@"out_trade_no"];//商户订单号,必填 [params setObject:PartnerID forKey:@"mch_id"]; // 商户ID [params setObject:[self zh_getIPAddress:YES] forKey:@"spbill_create_ip"];//终端ip,必填 [params setObject:@"1" forKey:@"total_fee"]; //签名 [params setObject:[self zh_genSign:params] forKey:@"sign"]; return params;}// 将字符串MD5加密- (NSString *)zh_md5:(NSString *)str{ // #import <CommonCrypto/CommonDigest.h> // MD5加密需要导此包 const char *cStr = str.UTF8String; unsigned char digest[CC_MD5_DIGEST_LENGTH]; CC_MD5(cStr, strlen(cStr), digest); NSMutableString *md5Str = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [md5Str appendFormat:@"%02x", digest[i]]; } return md5Str;}// 签名- (NSString *)zh_genSign:(NSDictionary *)signParams{ // 排序 NSArray *keys = [signParams allKeys]; NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { return [obj1 compare:obj2 options:NSNumericSearch]; }]; // 生成 NSMutableString *sign = [NSMutableString string]; for (NSString *key in sortedKeys) { [sign appendString:key]; [sign appendString:@"="]; [sign appendString:[signParams objectForKey:key]]; [sign appendString:@"&"]; } [sign appendString:@"key="]; [sign appendString:APISignKey];// 注意:不能hardcode在客户端,建议genPackage这个过程都由服务器端完成 NSString *result = [[self zh_md5:sign] uppercaseString]; return result;}// 获取终端IP地址- (NSString *)zh_getIPAddress:(BOOL)preferIPv4{ /* 需要引入一下头文件及定义宏 #include <ifaddrs.h> #include <arpa/inet.h> #include <net/if.h> #define IOS_CELLULAR @"pdp_ip0" #define IOS_WIFI @"en0" #define IOS_VPN @"utun0" #define IP_ADDR_IPv4 @"ipv4" #define IP_ADDR_IPv6 @"ipv6" */ NSArray *searchArray = preferIPv4 ? @[ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] : @[ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ; NSDictionary *addresses = [self zh_getIPAddresses]; __block NSString *address; [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) { address = addresses[key]; if(address) *stop = YES; } ]; return address ? address : @"0.0.0.0";}- (NSDictionary *)zh_getIPAddresses{ NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8]; // retrieve the current interfaces - returns 0 on success // 导入ifaddrs.h struct ifaddrs *interfaces; if(!getifaddrs(&interfaces)) { // Loop through linked list of interfaces struct ifaddrs *interface; for(interface=interfaces; interface; interface=interface->ifa_next) { if(!(interface->ifa_flags & IFF_UP) || (interface->ifa_flags & IFF_LOOPBACK)) { continue; // deeply nested code harder to read IFF_UP需要导入头文件 } const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr; if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) { NSString *name = [NSString stringWithUTF8String:interface->ifa_name]; char addrBuf[INET6_ADDRSTRLEN]; if(inet_ntop(addr->sin_family, &addr->sin_addr, addrBuf, sizeof(addrBuf))) { NSString *key = [NSString stringWithFormat:@"%@/%@", name, addr->sin_family == AF_INET ? IP_ADDR_IPv4 : IP_ADDR_IPv6]; addresses[key] = [NSString stringWithUTF8String:addrBuf]; } } } // Free memory freeifaddrs(interfaces); } // The dictionary keys have the form "interface" "/" "ipv4 or ipv6" return [addresses count] ? addresses : nil;}#pragma mark - 微信支付(不包括服务器, 正常的操作流程就需要这一个方法即可)- (void)zh_weChatPay{ if (![WXApi isWXAppInstalled]) { NSLog(@"未安装微信客户端"); return; } if (![WXApi isWXAppSupportApi]) { NSLog(@"不支持微信支付"); return; } // 此处的请求可以替换为AFNetworking的请求 NSString *urlString = @"http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // 向自己的服务器请求订单生成预支付订单信息 NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setHTTPMethod:@"POST"]; // body: 商品描述 // out_trade_no: 商品订单流水号 // spbill_create_ip: 终端IP地址 // total_fee: 商品价格 单位: 分 NSString *outTradNo = [NSString stringWithFormat:@"%d", arc4random() % 10000]; NSString *out_trade_no= [NSString stringWithFormat:@"%@%@",[NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]],outTradNo]; // 随机生成商户订单号 NSString *bodyString = [NSString stringWithFormat:@"body=商品的描述&out_trade_no=%@&spbill_create_ip=%@&total_fee=1", out_trade_no, [self zh_getIPAddress:YES]]; NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; [request setHTTPBody:bodyData]; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; if ([[NSString stringWithFormat:@"%@", result[@"opflag"]] isEqualToString:@"1"]) { NSError *error = nil; NSDictionary *xmlDict = [[XMLReader dictionaryForXMLString:result[@"weixinPost"] error:&error] objectForKey:@"xml"]; //调用支付接口 PayReq *payRequest = [[PayReq alloc]init]; payRequest.partnerId = [[xmlDict objectForKey:@"mch_id"] objectForKey:@"text"]; payRequest.prepayId = [[xmlDict objectForKey:@"prepay_id"] objectForKey:@"text"]; payRequest.package = @"Sign=WXPay"; payRequest.nonceStr = [[xmlDict objectForKey:@"nonce_str"] objectForKey:@"text"]; payRequest.timeStamp = [[NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]] intValue]; //构造参数列表,再次签名 NSMutableDictionary *payDict = [NSMutableDictionary dictionary]; [payDict setObject:WeChatAppID forKey:@"appid"]; [payDict setObject:payRequest.nonceStr forKey:@"noncestr"]; [payDict setObject:payRequest.package forKey:@"package"]; [payDict setObject:payRequest.partnerId forKey:@"partnerid"]; [payDict setObject:payRequest.prepayId forKey:@"prepayid"]; [payDict setObject:[NSString stringWithFormat:@"%u", (unsigned int)payRequest.timeStamp] forKey:@"timestamp"]; payRequest.sign = [self zh_genSign:payDict]; if ([WXApi sendReq:payRequest]) // 调起微信客户端支付 { NSLog(@"调起微信支付成功!"); } else { NSLog(@"调起微信支付失败!"); } } else { NSLog(@"调起微信支付失败!"); }}#pragma mark -- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning];}@end
第十步: 在AppDelegate.m中添加支付完成回调, 此处会在回调中触发一个通知.
// NOTE: 8.0使用API接口- (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;}// NOTE: 9.0以后使用新API接口- (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;}// 微信支付- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{ return [WXApi handleOpenURL:url delegate:self];}- (void)onResp:(BaseResp *)resp{ if([resp isKindOfClass:[PayResp class]]) { [[NSNotificationCenter defaultCenter] postNotificationName:@"doWeChatPayResult" object:resp]; }}
第十一步: 回调的时候需要触发一个代理, 签代理<WXApiDelegate>
第十二步: 在ViewController.m的viewDidLoad方法中注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(zh_handleWeChatPayResult:) name:@"doWeChatPayResult" object:nil];
第十三步: 通知触发方法, 做支付结果操作
- (void)zh_handleWeChatPayResult:(NSNotification *)notification{ BaseResp *resp = notification.object; switch (resp.errCode) { case WXSuccess: NSLog(@"支付成功"); break; default: NSLog(@"支付失败"); break; }}
最后附个demo地址: https://github.com/MrZhou1990/ZHWeChatPay.git
0 0
- iOS 微信支付 SDK版本1.7.5(2016年12月27日)
- iOS微信支付SDK开发经验
- 微信支付新规确认收费,12月1日执行,网友:一年损失5万!
- iOS开发:集成微信 SDK 支付篇
- 微信支付找不到sdk
- 微信APP支付SDK
- Android微信支付SDK
- 微信移动支付接口申请——2016年5月版
- iOS微信APP支付V3版本源码
- iOS微信支付
- IOS:微信支付
- iOS微信支付
- IOS-微信支付
- ios -- 微信 支付
- 微信支付iOS
- iOS 微信支付
- iOS微信支付
- iOS--微信支付
- Android实现一个简单的手电筒
- VS代码自动排版快捷键
- 常见sql注入的防范总结
- 关于如何给 github 上其他仓库贡献代码
- 关键字杀进程
- iOS 微信支付 SDK版本1.7.5(2016年12月27日)
- LTE 架构
- 设计模式之浅析
- ubuntu 16.10下软件记录
- ubuntu 菜单栏移到下方
- Java_容器_Collection_增强for循环
- iOS - 开发中监听系统键盘删除按钮 , 回车按钮小技巧
- Eclipse构建Maven项目
- 《C++ Primer Plus(第六版)》(28)(第十四章 C++中的代码重用 笔记)