關(guān)于微信支付疾掰,我就忍不住要吐槽兩句,因?yàn)轫?xiàng)目中要用到微信支付徐紧,所以就從官方下載了微信支付的demo静檬,自我感覺微信支付的demo和官方文檔寫的挺讓人回味的,因?yàn)槟憧戳艘院蟪燥埖臅r候也會忍不住罵上兩句并级。
好了拂檩,廢話不多說,接下來我們直接上代碼
在appdelegate中代碼如下
#import "AppDelegate.h"
//微信支付
#import "WXApi.h"
@interface AppDelegate ()<WXApiDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//注冊微信支付
[WXApi registerApp:APP_id withDescription:@"demo"];
return YES;
}
//iOS9 之后使用這個回調(diào)方法嘲碧。
- (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;
}
#pragma mark - 微信支付的代理方法
- (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
{
if ([url.host isEqualToString:@"pay"]) {
return [WXApi handleOpenURL:url delegate:self];
}
return YES;
}
#pragma mark - 微信支付成功的回調(diào)函數(shù)(這個方法必須寫在delegate.m文件中)
-(void)onResp:(BaseResp*)resp
{
if ([resp isKindOfClass:[PayResp class]]){
PayResp *response = (PayResp*)resp;
switch(response.errCode){
case WXSuccess:
//服務(wù)器端查詢支付通知或查詢API返回的結(jié)果再提示成功
//NSLog(@"支付成功");
//發(fā)送通知給帶有微信支付功能的視圖控制器稻励,告訴他支付成功了,請求后臺訂單狀態(tài)愈涩,如果后臺返回的訂單也是成功的狀態(tài)望抽,那么可以進(jìn)行下一步操作
[[NSNotificationCenter defaultCenter] postNotificationName:WEIXINPAYSUCCESSED object:nil userInfo:nil];
break;
default:
/*
resp.errCode = 2 用戶取消支付
resp.errCode = -1 錯誤
*/
NSLog(@"支付失敗,retcode=%d ---- %@",resp.errCode,resp.errStr);
break;
}
}
}//微信支付成功的回調(diào)方法(回調(diào)函數(shù))
上面有兩個系統(tǒng)回調(diào)的方法履婉,第一個是針對ios9.0以后煤篙,第二個是針對ios9.0之前的
在帶有微信支付的頁面我們做如下處理
#import "ViewController.h"
//微信支付
#import "WXApi.h"
#import "payRequsestHandler.h"
#import "WXUtil.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(60, 100, 180, 100)];
button.backgroundColor = [UIColor redColor];
[button setTitle:@"微信支付" forState:UIControlStateNormal];
[button addTarget:self action:@selector(test) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
//接受成功的通知
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(succeed) name:WEIXINPAYSUCCESSED object:nil];
}
#pragma mark - ASction Methods
- (void)test
{
payRequsestHandler *handle = [[payRequsestHandler alloc]init];
if ( [handle init:APP_id mch_id:MCH_id]) {
NSLog(@"初始化成功");
}
//設(shè)置商戶密鑰
[handle setKey:PARTNER_id];
//提交預(yù)支付,獲得prepape_id
NSString *order_name = @"測試"; //訂單標(biāo)題
NSString *order_price = @"1";//測試價格 分為單位
NSString *nocify_URL = nocify_url; //回調(diào)借口
NSString *noncestr = [NSString stringWithFormat:@"%d", rand()]; //隨機(jī)串
NSString *orderno = [NSString stringWithFormat:@"%ld",time(0)];
NSMutableDictionary *params = [@{@"appid":APP_id,
@"mch_id":MCH_id,
@"device_info":[[[UIDevice currentDevice] identifierForVendor] UUIDString],
@"nonce_str":noncestr,
@"trade_type":@"APP",
@"body":order_name,
@"notify_url":nocify_URL,
@"out_trade_no":orderno,//商戶訂單號:這個必須用后臺的訂單號
@"spbill_create_ip":@"8.8.8.8",
@"total_fee":order_price}mutableCopy];
//提交預(yù)支付兩次簽名得到預(yù)支付訂單的id(每次的請求得到的預(yù)支付訂單id都不同)
NSString *prepate_id = [handle sendPrepay:params];
//提交預(yù)訂單成功
if (prepate_id != nil) {
PayReq *request = [[PayReq alloc]init];
//商家id
request.partnerId = MCH_id;
//訂單id
request.prepayId = prepate_id;
//擴(kuò)展字段(官方文檔:暫時填寫固定值)
request.package = @"Sign=WXPay";
//隨機(jī)字符串
request.nonceStr = noncestr;
//時間戳
request.timeStamp = (UInt32)[[NSDate date] timeIntervalSince1970];
//sign參數(shù)(很經(jīng)常出現(xiàn)的問題:就是調(diào)起支付到微信那邊只出現(xiàn)一個確定按鈕毁腿,單擊確認(rèn)按鈕直接返回到app辑奈,出現(xiàn)這個問題100%是sign參數(shù)的問題)
/*
參數(shù)依次是: appid_key、partnerid_key已烤、prepayid_key鸠窗、固定值Sign=WXPay、預(yù)支付的隨機(jī)數(shù)(跟上面得到預(yù)支付訂單的隨機(jī)數(shù)要一致)胯究、支付時間(秒)
*/
request.sign = [self createMD5SingForPay:APP_id partnerid:MCH_id prepayid:prepate_id package:@"Sign=WXPay" noncestr:noncestr timestamp:(UInt32)[[NSDate date] timeIntervalSince1970]];
//帶起微信支付
if ([WXApi sendReq:request]) {
// NSLog(@"走這里啊");
}else{
//NSLog(@"走之類");
//未安裝微信客戶端
// [[[UIAlertView alloc]initWithTitle:@"測試demo" message:@"您還未安裝微信客戶端,請前往Appstore下載或者選擇其他支付方式!" delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]show];
}
}
}//點(diǎn)擊微信支付
#pragma mark - Private Methods
-(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",(unsigned int)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 *result = [self md5:contentString];
return result;
}//創(chuàng)建發(fā)起支付時的sige簽名
-(NSString *)md5:(NSString *)str
{
const char *cStr = [str UTF8String];
unsigned char result[16]= "0123456789abcdef";
CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
//這里的x是小寫則產(chǎn)生的md5也是小寫稍计,x是大寫則md5是大寫,這里只能用大寫裕循,微信的大小寫驗(yàn)證很逗
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]
];
}//MD5 加密
- (void)succeed
{
NSLog(@"支付成功");
}//支付成功的監(jiān)聽方法
#pragma mark - OverRide Methods
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:WEIXINPAYSUCCESSED object:nil];
}//移除通知
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
這里面有幾個名字我給大家解釋一下丙猬,PARTNER_id是從商戶中心那里獲取的,當(dāng)你在微信開放平臺創(chuàng)建的應(yīng)用申請微信支付成功以后费韭,進(jìn)入到商戶中心那里自己設(shè)置一個32位的字符串茧球。MCH_id是商家的id,也就是商戶號星持。
APP_id是在微信開放平臺創(chuàng)建應(yīng)用的appid抢埋。notify_url是回調(diào)接口,也就是一個url鏈接督暂,是由服務(wù)器給你的
最后還有一點(diǎn)揪垄,大家通常會遇到一個問題,在調(diào)起微信以后逻翁,發(fā)現(xiàn)只有一個空白的頁面饥努,中間有一個確定的按鈕,這種情況是sign簽名的問題
下面附上微信支付的demo八回,里面的一些相關(guān)信息需要換成自己開放平臺中自己應(yīng)用的信息
https://github.com/EngineerLXK/WeiXinPay