6如何微信支付 ios

2018-01-11 14:42:13 qq_30746437 阅读数 9908

场景介绍
H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付。
主要用于触屏版的手机浏览器请求微信支付的场景。可以方便的从外部浏览器唤起微信支付。
提醒:H5支付不建议在APP端使用,如需要在APP中使用微信支付,请接APP支付。

这个场景介绍来自微信H5支付的开发文档,说建议不要在APP端使用H5支付,但是确实有这样的需求,我们来看看该怎么办?

因为是直接通过网页链接调用,所以我们的APP并没有在微信SDK去注册,也并没有传输给微信对应的scheme,然后iOS的进程调用就是通过schme实现的。所以可以肯定的是在iOS APP发起H5微信支付这个需求,是不能实现微信向APP的回调跳转,因为调用了H5支付后,微信并不知道是哪个APP发生了这个操作,本来H5支付就是默认的网页支付和APP没有任何关系,我们现在只是在APP中打开了这个网页而已。
回调实现不了,我们来看看能不能从APP通过网页向微信客户端跳转,还是温习一下iOS的进程跳转,通过给APP标识对应的scheme,然后调用openURL,传输scheme:xxxxx格式的URL完成对该APP的调用。这个scheme,有点类似http的一种协议,微信的APP的scheme为weixin。

我们正常通过WKWebView打开支付网页完成支付跳转,发现无法完成跳转。在看网页返回了weixin:payxxxxxx样式的链接,然后没有反应,说明WKWebView识别不了weixin:协议,需要我们手动处理一下,直接上代码,如图:
这里写图片描述
这样的话,就能正常完成跳转到微信客户端了。

经过实验发现,使用UIWebView可以通过weixin:xxxx格式的链接调用微信客户端。但是如果是先进入的是http:xxxx协议的网页,通过操作在返回给网页weixin:xxxx链接继续访问,则无论是在UIWebView和WEWebView下都不能完成对微信客户端的跳转。同样需要以上处理。

关于网页开发对WKWebView的适配,大家可以参靠一下:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1483682025_enmey

2018-07-12 14:15:52 cdy15626036029 阅读数 1358

1. 准备

微信平台分为微信公众平台微信开放平台,公众平台是运营微信公众号的管理系统,开放平台主要针对app、网站开发,提供登录、分享、支付等功能。

注册开放平台之后,新建应用,填写应用信息(Android、iOS等信息),创建之后需要等待审核(这个审核很快的,几个小时就通过了)。

然后是为该应用申请支付功能,要注意个人是无法申请的,具体可参考微信支付申请条件和资格。这里牵涉到一系列公司资质的审核和费用支付,需要几个工作日的时间

完成之后可以获取到appid(微信开放平台为应用生成的唯一识别码)、商户id、商户secretKey。对于app端来说只用到appid,商户id最好通过接口从server获取,商户secretKey是用来签名的,一般只有server能用到。

2. 支付流程

先上一个开放平台给出的流程图:


支付流程.png

这个图很实用很详细很清晰,但一开始看可能会觉得复杂。其实对开发者来说,比较关心的流程是:

app向server发起支付请求

server收到请求后向微信后台调用统一下单API,获得预付单信息

server生成带签名的客户端支付信息并返回给app

用户确认支付,app调起微信客户端进行支付

app获得支付结果后向server查询最终结果并显示

流程了解之后,了解下需要定义的接口和前后端的具体工作:

新接口:

app向server发起请求,获得签名后的app支付信息

app支付之后向server查询支付结果(微信回调的结果不可信,必须以server的结果为准)

app需要做的:

项目接入微信支付sdk

向server请求支付信息

用支付信息调起微信客户端,然后支付

收到微信回调之后向server查询支付结果

根据支付结果展示页面

server需要做的:

收到app端支付请求后调用统一下单API向微信后台获取预支付信息

将app端需要的支付信息签名之后返回给app

接收微信后台回调信息(支付结果),以供app查询

3. iOS开发

开发文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1

下载并运行demo

其实把demo看明白了,直接运用到自己的app里,也不是不可以的

设置项目

在Xcode中,projectName-->Info-->URL Types 添加appid。设置之后才能实现应用间跳转


urltypes.png

导入sdk


sdk.png

如果使用了pod,直接在Podfile中添加pod 'WechatOpenSDK' 然后执行 pod update即可。如果没有使用pod,在添加了sdk文件包之后,需要在pojectName-->General-->Linked Frameworks and Libraries 中添加相应内容


libs.png

代码

AppDelegate.m

didFinishLaunchingWithOptions方法中

[WXApi registerApp:@"wx000999888777"];//注册appid

openUrl、handleOpenURL方法

- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {

return[WXApi handleOpenURL:url delegate:[PaymentManager sharedManager]];}

- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation {

return[WXApi handleOpenURL:url delegate:[PaymentManager sharedManager]];

}

//NOTE:9.0以后使用新API接口

- (BOOL)application:(UIApplication*)app openURL:(NSURL*)url options:(NSDictionary *)options{

return[WXApi handleOpenURL:url delegate:[PaymentManager sharedManager]];

}

如果之前项目中使用了友盟等第三方框架,直接并排写就可以:

- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url{    [WXApi handleOpenURL:url delegate:[PaymentAction sharedPayment]];    [UMSocialSnsService handleOpenURL:url];returnYES;}

另外,这个地方的delegate也可以直接设置成nil,表示用当前AppDelegate作为微信支付的代理,这样一来支付回调写在AppDelegate.m中即可。

但不推荐这种做法,我是设置了PaymentManager作为代理,这是项目中专门管理支付的一个类,包括之前的支付宝支付。这也是微信demo中的做法。(支付宝是用block获取回调的,个人感觉代码更紧凑,不容易乱;微信是用的代理,刚开始看晕乎乎的)

PaymentManager

首先是遵守协议WXApiDelegate

然后在PayVC中通过接口获取支付信息

然后调起微信客户端:

- (void)weiXinPayWithDic:(NSDictionary *)wechatPayDic {   

     PayReq *req = [[PayReq alloc] init];   

     req.openID = [wechatPayDic objectForKey:@"appId"];   

     req.partnerId = [wechatPayDic objectForKey:@"partnerId"];  

      req.prepayId = [wechatPayDic objectForKey:@"prepayId"];  

      req.package= [wechatPayDic objectForKey:@"packages"];   

     req.nonceStr = [wechatPayDic objectForKey:@"nonceStr"];   

     req.timeStamp = [[wechatPayDic objectForKey:@"timesTamp"] intValue];

       req.sign = [wechatPayDic objectForKey:@"sign"];  

      [WXApi sendReq:req];

}

这里的数据wechatPayDic一定是server经过二次签名的

回调

// 微信支付返回结果回调

- (void)onResp:(BaseResp *)resp {if([resp isKindOfClass:[PayRespclass]]) {   

             PayResp *response = (PayResp *)resp;

if(_delegate && [_delegate respondsToSelector:@selector(managerDidRecvPaymentResponse:)]) {    

        [_delegate managerDidRecvPaymentResponse:response];      

  }  

  }}

当然前提是在PaymentManager.h中已经定义了代理:

@protocolWXApiManagerDelegate@required

- (void)managerDidRecvPaymentResponse:(PayResp *)response;@end@interfacePaymentManager:NSObject@property(nonatomic,assign)id delegate;

这个代理是用来处理回调结果,展示页面的,所以设置成PayVC控制器

处理回调结果

PayVC.m

遵守协议WXApiManagerDelegate

在viewDidLoad中设置[PaymentManager sharedManager].delegate = self;

- (void)managerDidRecvPaymentResponse:(PayResp *)response {switch(response.errCode) {

caseWXSuccess:                [selfcheckWechatPayResult];break;caseWXErrCodeUserCancel:          

      [[HintManager shareManager] showHint:@"中途取消"];break;default:{        

        [[HintManager shareManager]showHint:@"支付失败"];       

     }break;     

   }}

然后在checkWechatPayResult向server查询支付结果,刷新页面

哦了~~ 泼佛客特

4. 出现的问题

当然了,并不泼佛客特

系统版本大于等于iOS9的,调起微信客户端之后,可以直接点击状态栏左侧按钮返回,这时是不走回调方法的。

这样在支付成功之后,不走回调方法,就无法知道支付状态,当前页面无法给出提示。

解决方案是,在AppDelegate.m的applicationWillEnterForeground方法中,调用查询支付结果接口然后刷新当然页面。需要设置bool变量作为标志,否则每次应用进入前台都去查询,就不符合业务要求了。

进入微信支付页面之后,不做操作,切换到自己应用中,退出当前支付页面,然后再进入微信客户端点击支付或者取消,此时自己的应用会崩溃闪退

原因是退出页面后页面已经出栈被销毁,但wx回调时还是去调用其中的代理方法,就会出现野指针。

解决方法是,在页面的viewWillDisappear方法中加入[PaymentManager sharedManager].delegate = nil;。

5. 需要注意的点

一定设置好scheme,否则应用无法跳转

在调起微信支付使用的PayReq类,一定要用WXApi中自带的类,不要自己创建新类。我之前自己创建的类,定义了同样的变量,同样继承了BaseReq,然并卵,sendReq方法一直返回false

调起微信支付的数据,一定是server经过二次签名的,不要把调用统一下单API获取到的数据直接返给app

虽然类中的变量命名是驼峰式,但签名时的key值全部是小写的,签名时不要忘了后面加上商户key。

6. 签名

可能某些server端由于这样那样的原因不愿意做二次签名,app可以自己做。(不过因为签名需要用到secretKey,让app端做签名是有风险的)

下面是签名代码:




个人建议像微信支付、支付宝支付最后都由后台完成,提交相应的数据给后台,让后台生成订单并返回以下参数就可以了,这样微信就会异步通知后台  支付完成后返回APP  由APP直接向后台请求订单支付成功了没有, 这样可以保证支付不会出现一些小问题  



2016-03-24 17:20:44 woxinqidai 阅读数 369

 

 

微信公众号支付, 统一下单 body 中如果有(乱码\一些特殊字符之类),

 

 ios微信客户端下会调用绑定银行卡的界面, 

 

实际上银行卡已经绑定, 此处应该是微信的一个bug

 

 

 

 

 

2017-06-09 14:59:29 qq_24529085 阅读数 4391
近段时间都在搞unity接sdk,上篇记了unity接入微信支付android端,URL:unity接入微信支付-Android篇   这几天又在搞ios端,难过各种坑啊。。。。。C。。。OC。。。作为一个unity开发搞c#的开发者,看到复杂的OC,就懵逼了再见。没办法mac用openstepd的标准。。

此处有惊喜 对的,这就是一个完整的微信支付xcode工程羡慕,微信签名下单是在app端,只需要把appid等商户信息改成自己的就可以跑起来。

下面说下unity调用;
1.unity发布xcode工程

引入using System.Runtime.InteropServices;  

  [DllImport("__Internal")]  

private static extern void wxpaytest();  

public void ClickBtn()  

{

wxpaytest();

}

 场景中拉一个button,把ClickBtn挂上去;然后就可以build。

2.xcode部分

把上面下载的工程里面的文件右键加入工程;参照原工程文件把加入链接库。




在UnityAppController.mm的didFinishLaunchingWithOptions 下加入微信注册:

//注册微信支付
         [WXApi registerApp:APP_id withDescription:@"demo"];


在ViewController中加入unity调用的方法wxpaytest

此方法要用c的方式写入,unity才能成功调起(自己测试是这个样的),由于要从c中调用oc中的方法,在网上找了几种,但是测试没成功尴尬,所以就把全部流程卸载了wxpaytest中。。

 #import "SuperViewController.h"
//微信支付
#import "lib/payRequsestHandler.h"
#import "lib/WXUtil.h"
#import "WXSDK/WXApi.h" 

 
extern "C" void wxpaytest() 


{
 payRequsestHandler *handle = [[payRequsestHandler alloc]init];          if ( [handle  init:APP_id mch_id:MCH_id]) {                  NSLog(@"初始化成功");     }          //设置商户密钥     [handle setKey:PARTNER_id];     //提交预支付,获得prepape_id     NSString *order_name = @"测试";   //订单标题     NSString *order_price = @"1";//测试价格 分为单位     NSString *nocify_URL = nocify_url;    //回调借口     NSString *noncestr  = [NSString stringWithFormat:@"%d", rand()]; //随机串     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];          //提交预支付两次签名得到预支付订单的id(每次的请求得到的预支付订单id都不同)     NSString *prepate_id = [handle sendPrepay:params];               //提交预订单成功     if (prepate_id != nil) {                  PayReq *request = [[PayReq alloc]init];                  //商家id         request.partnerId = MCH_id;                  //订单id         request.prepayId = prepate_id;                  //扩展字段(官方文档:暂时填写固定值)         request.package = @"Sign=WXPay";                  //随机字符串         request.nonceStr = noncestr;                  //时间戳         request.timeStamp = (UInt32)[[NSDate date] timeIntervalSince1970];                  //sign参数(很经常出现的问题:就是调起支付到微信那边只出现一个确定按钮,单击确认按钮直接返回到app,出现这个问题100%是sign参数的问题)         /*          参数依次是: appid_key、partnerid_key、prepayid_key、固定值Sign=WXPay、预支付的随机数(跟上面得到预支付订单的随机数要一致)、支付时间(秒)                    */         //request.sign = [selfClass createMD5SingForPay:APP_id partnerid:MCH_id prepayid:prepate_id package:@"Sign=WXPay" noncestr:noncestr timestamp:(UInt32)[[NSDate date] timeIntervalSince1970]];       
NSMutableDictionary *signParams = [NSMutableDictionary dictionary];         [signParams setObject:APP_id forKey:@"appid"];         [signParams setObject:noncestr forKey:@"noncestr"];         [signParams setObject:@"Sign=WXPay" forKey:@"package"];         [signParams setObject:MCH_id forKey:@"partnerid"];         [signParams setObject:prepate_id forKey:@"prepayid"];         [signParams setObject:[NSString stringWithFormat:@"%u",(unsigned int)(UInt32)[[NSDate date] timeIntervalSince1970]] 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 *resul = [self md5:contentString];                  const char *cStr = [contentString UTF8String];         unsigned char result[16]= "0123456789abcdef";         CC_MD5(cStr, (CC_LONG)strlen(cStr), result);         //这里的x是小写则产生的md5也是小写,x是大写则md5是大写,这里只能用大写,微信的大小写验证很逗         NSString *resul = [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]                            ];                request.sign = resul;                  //带起微信支付         if ([WXApi sendReq:request]) {                                       NSLog(@"走这里啊");                      }else{                          NSLog(@"走之类");             //未安装微信客户端             //            [[[UIAlertView alloc]initWithTitle:@"测试demo" message:@"您还未安装微信客户端,请前往Appstore下载或者选择其他支付方式!" delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]show];                      }                  //接受成功的通知         [[NSNotificationCenter defaultCenter]addObserver:selfClass selector:@selector(succeed) name:WEIXINPAYSUCCESSED object:nil];                  NSLog(@"wanc");

2018-08-03 10:36:21 a4475686 阅读数 1554

最近在做微信公众号支付,但是出了点情况。

问题描述:在IOS端微信浏览器调起微信支付(wx.choosewxpay)没有问题正常调起,而在安卓端微信支付点击后先是弹出的微信经典的支付小黑块,然后就立马就返回支付失败的通知了。但是通过微信的调试模式,看到配置是没问题的。但是却看到了{"errMsg":"chooseWXPay:fail"}的提示。

解决方式:其实网上也有答案,但是说的比较模糊确实是目录问题。微信支付要求支付发起的页面为最后一级的目录。打个比方,如果你的支付调起页面是pay.html,而访问这个支付页面的路径为:www.XXXX.com/paytest/pay.html,那么你的这个pay.html就是放在了paytest文件目录下,那就是说paytest为支付发起的最后一级目录,那么你就需要保证这个目录下没有其他存放了html的目录了。也就是说你的paytest目录里不能再存在一个XXX目录,然后这个xxx目录里面又放了其他一个xxx.html,那么此时你的最后一级目录就变为了XXX你需要把支付页面放到这个XXX目录里,也就是访问路径为:www.XXXX.com/paytest/XXX/pay.html。通过这种方式解决了我遇到的安卓无法调起的问题,然后ios端依然正常调起。

ps:我们前端使用的是vue,使用的模式是用history模式,然后前端喜欢用/xxxx/xx/param进行带值,然后xxxx是最后一级,然后前端该为/xxxx/xx?param=param后就正常了。