http://blog.csdn.net/u012131769/article/details/76637890
微信APP支付(IOS手机端+java后台)版
0.介绍预览
针对需要在IOS手机上接入原生微信支付场景,调用微信进行支付。如图:
1.资料准备
1.1 账号注册
打开https://open.weixin.qq.com,注册微信开放平台开发者账号
1.2 开发者认证
登录,进入账号中心,进行开发者资质认证。
1.3 注册应用
认证完成后,进入管理中心,新建移动应用。填写应用资料,其中android版应用签名可通过扫码安装温馨提供的应用获得,详细参考微信文档。创建完成后点击查看,申请开通微信支付。一切准备就绪!
2.Java后台开发
添加依赖
- <!-- 微信支付依赖 -->
- <dependency>
- <groupId>org.xmlpull</groupId>
- <artifactId>xmlpull</artifactId>
- <version>1.1.3.1 </version>
- </dependency>
- <dependency>
- <groupId>net.sf.json-lib</groupId>
- <artifactId>json-lib</artifactId>
- <version>2.3</version>
- <classifier>jdk15</classifier>
- </dependency>
- <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
- <dependency>
- <groupId>com.thoughtworks.xstream</groupId>
- <artifactId>xstream</artifactId>
- <version>1.4.5</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/com.ning/async-http-client -->
- <dependency>
- <groupId>com.ning</groupId>
- <artifactId>async-http-client</artifactId>
- <version>1.8.13</version>
- </dependency>
生成统一订单
- @RequestMapping(value="/pay/wxpay/params",produces="application/json;charset=utf-8")
- @ResponseBody
- public String signprams(HttpServletRequest request){
- String res = "{code:404}";
- try{
- // 充值金额
- String account = request.getParameter("account");
- // 用户id
- String sid = request.getParameter("sid");
- String subject = "订单标题";
- String body = "订单描述";
- int acc = (int) (Double.valueOf(account) * 100);
- String appid = "您的APPID";
- String out_trade_no = "生成您的订单号";
- // 生成订单数据
- SortedMap<String, String> payMap = genOrderData(request, subject, body, acc, appid, out_trade_no);
- savePayLog(out_trade_no,account,sid,body,payMap.get("paySign"),nid,2);
- // 4.返回数据
- res = buildPayRes(payMap,out_trade_no);
- }catch (Exception e){
- e.printStackTrace();
- res = "{code:500}";
- }
- return res;
- }
- private SortedMap<String, String> genOrderData(HttpServletRequest request, String subject, String body,
- int acc, String appid, String out_trade_no)
- throws IOException, ExecutionException, InterruptedException, XmlPullParserException {
- SortedMap<String, String> paraMap = new TreeMap<String, String>();
- paraMap.put("appid", appid);
- paraMap.put("attach", subject);
- paraMap.put("body", body);
- paraMap.put("mch_id", "您的商户id,到商户平台查看");
- paraMap.put("nonce_str", create_nonce_str());
- paraMap.put("notify_url", "http://pay.xxxxx.com/pay/wxpay/notify.htm ");// 此路径是微信服务器调用支付结果通知路径
- paraMap.put("out_trade_no", out_trade_no);
- paraMap.put("spbill_create_ip", request.getRemoteAddr());
- paraMap.put("total_fee", acc+"");
- paraMap.put("trade_type", "APP");
- String sign = createSign(paraMap);
- paraMap.put("sign", sign);
- // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
- String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- String xml = getRequestXml(paraMap);
- String xmlStr = HttpKit.post(url, xml);
- // 预付商品id
- String prepay_id = "";
- if (xmlStr.indexOf("SUCCESS") != -1) {
- Map<String, String> map = WXRequestUtil.doXMLParse(xmlStr);
- prepay_id = (String) map.get("prepay_id");
- }
- SortedMap<String, String> payMap = new TreeMap<String, String>();
- payMap.put("appid", appid);
- payMap.put("partnerid", "您的商户id,到商户平台查看");
- payMap.put("prepayid", prepay_id);
- payMap.put("package", "Sign=WXPay");
- payMap.put("noncestr", create_nonce_str());
- payMap.put("timestamp", WXRequestUtil.create_timestamp());
- String paySign = createSign(payMap);
- payMap.put("paySign", paySign);
- return payMap;
- }
- //请求xml组装
- public static String getRequestXml(SortedMap<String,String> parameters){
- String sign = "";
- StringBuffer sb = new StringBuffer();
- sb.append("<xml>");
- Set es = parameters.entrySet();
- Iterator it = es.iterator();
- while(it.hasNext()) {
- Map.Entry entry = (Map.Entry)it.next();
- String key = (String)entry.getKey();
- String value = (String)entry.getValue();
- // if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
- // sb.append("<"+key+">"+value+"</"+key+">");
- // }
- if ("sign".equalsIgnoreCase(key)){
- sign = "<"+key+">"+value+"</"+key+">";
- }else {
- sb.append("<"+key+">"+value+"</"+key+">");
- }
- }
- sb.append(sign);
- sb.append("</xml>");
- return sb.toString();
- }
- //生成签名
- public String createSign(SortedMap<String,String> parameters){
- StringBuffer sb = new StringBuffer();
- Set es = parameters.entrySet();
- Iterator it = es.iterator();
- while(it.hasNext()) {
- Map.Entry entry = (Map.Entry)it.next();
- String k = (String)entry.getKey();
- Object v = entry.getValue();
- if(null != v && !"".equals(v)
- && !"sign".equals(k) && !"key".equals(k)) {
- sb.append(k + "=" + v + "&");
- }
- }
- sb.append("key=" + WXConfig.APP_PERTNER_KEY);
- System.out.println(sb.toString());
- String sign = MD5Utils.MD5Encode(sb.toString(),"UTF-8").toUpperCase();
- return sign;
- }
- public String create_nonce_str() {
- String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- String res = "";
- for (int i = 0; i < 32; i++) {
- Random rd = new Random();
- res += chars.charAt(rd.nextInt(chars.length() - 1));
- }
- return res;
- }
3.IOS客户端开发
导入微信开发包
添加URL Types
在AppDelegate.m中注册应用
- #import "AppDelegate.h"
- #import "XSTabBarViewController.h"
- #import <AlipaySDK/AlipaySDK.h>
- #import "WXApi.h"
- @interface AppDelegate ()<WXApiDelegate>
- @end
- @implementation AppDelegate
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- // Override point for customization after application launch.
- // [NSThread sleepForTimeInterval:2.0];
- // 进入主控制器
- self.window = [[UIWindow alloc] init];
- self.window.frame = [UIScreen mainScreen].bounds;
- self.window.rootViewController = [[XSTabBarViewController alloc] init];
- [self.window makeKeyAndVisible];
- //向微信注册应用。
- [WXApi registerApp:@"wxfb96c2a9b531be26"];
- return YES;
- }
- -(void) onResp:(BaseResp*)resp
- {
- // NSLog(@" ----onResp %@",resp);
- /*
- ErrCode ERR_OK = 0(用户同意)
- ERR_AUTH_DENIED = -4(用户拒绝授权)
- ERR_USER_CANCEL = -2(用户取消)
- code 用户换取access_token的code,仅在ErrCode为0时有效
- state 第三方程序发送时用来标识其请求的唯一性的标志,由第三方程序调用sendReq时传入,由微信终端回传,state字符串长度不能超过1K
- lang 微信客户端当前语言
- country 微信用户当前国家信息
- */
- if ([resp isKindOfClass:[SendAuthResp class]]) //判断是否为授权请求,否则与微信支付等功能发生冲突
- {
- SendAuthResp *aresp = (SendAuthResp *)resp;
- if (aresp.errCode== 0)
- {
- // NSLog(@"code %@",aresp.code);
- [[NSNotificationCenter defaultCenter] postNotificationName:@"wechatDidLoginNotification" object:self userInfo:@{@"code":aresp.code}];
- }
- }else{ // 支付请求回调
- //支付返回结果,实际支付结果需要去微信服务器端查询
- NSString *strMsg = [NSString stringWithFormat:@"支付结果"];
- NSString *respcode = @"0";
- switch (resp.errCode) {
- case WXSuccess:
- strMsg = @"支付结果:成功!";
- // NSLog(@"支付成功-PaySuccess,retcode = %d", resp.errCode);
- respcode = @"1";
- break;
- default:
- strMsg = [NSString stringWithFormat:@"支付结果:失败!retcode = %d, retstr = %@", resp.errCode,resp.errStr];
- // NSLog(@"错误,retcode = %d, retstr = %@", resp.errCode,resp.errStr);
- respcode = @"0";
- break;
- }
- [[NSNotificationCenter defaultCenter] postNotificationName:@"wechatDidPayNotification" object:self userInfo:@{@"respcode":respcode}];
- }
- }
- //iOS 9.0 之前的处理方法不保证正确,如有错误还望指正
- - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
- {
- NSLog(@"iOS 9.0 之前");
- return [self applicationOpenURL:url];
- }
- -(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
- NSLog(@"iOS 9.0 之后");
- return [self applicationOpenURL:url];
- }
- - (BOOL)applicationOpenURL:(NSURL *)url
- {
- if([[url absoluteString] rangeOfString:@"wxfb96c2a9b531be26://pay"].location == 0){
- return [WXApi handleOpenURL:url delegate:self];
- }
- if ([url.host isEqualToString:@"safepay"])
- {
- [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:nil];
- return YES;
- }
- return YES;
- }
- }
在需要支付的Controller中接受微信支付通知
- - (void)viewDidLoad {
- [super viewDidLoad];
- // 接受微信支付通知
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wechatDidPayNotification:) name:@"wechatDidPayNotification" object:nil];
- }
向服务器端获取统一订单,并拉起微信进行支付
- -(void)weixinPay
- {
- NSString *userUrlStr = [NSString stringWithFormat:@"%@?sid=%@&account=%@&desc=%@", WX_PREPAY_URL, self.student.sid,self.payJinE,self.student.nid];
- NSURL *url = [NSURL URLWithString:userUrlStr];
- // NSLog(@"userUrlStr = %@", userUrlStr);
- NSURLRequest *request = [NSURLRequest requestWithURL:url];
- AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
- [MBProgressHUD showMessage:@"跳转中,请稍候"];
- [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) {
- [MBProgressHUD hideHUD];
- // NSLog(@"微信支付的response = %@", operation.responseString);
- NSData *JSONData = [operation.responseString dataUsingEncoding:NSUTF8StringEncoding];
- NSDictionary *userDict = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableLeaves error:nil];
- // 调用微信支付
- PayReq *request = [[PayReq alloc] init];
- /** 商家向财付通申请的商家id */
- request.partnerId = [userDict objectForKey:@"partnerid"];
- /** 预支付订单 */
- request.prepayId= [userDict objectForKey:@"prepayid"];
- /** 商家根据财付通文档填写的数据和签名 */
- request.package = [userDict objectForKey:@"package"];
- /** 随机串,防重发 */
- request.nonceStr= [userDict objectForKey:@"noncestr"];
- /** 时间戳,防重发 */
- request.timeStamp= [[userDict objectForKey:@"timestamp"] intValue];
- /** 商家根据微信开放平台文档对数据做的签名 */
- request.sign= [userDict objectForKey:@"sign"];
- self.sign = request.sign;
- self.ordnum = [userDict objectForKey:@"ordnum"];
- [WXApi sendReq: request];
- }failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- [MBProgressHUD hideHUD];
- NSLog(@"发生错误!%@",error);
- }];
- NSOperationQueue *queue = [[NSOperationQueue alloc] init];
- [queue addOperation:operation];
- }
- // 微信支付结果
- -(void)wechatDidPayNotification:(NSNotification *)notification
- {
- // NSLog(@"wechatDidPayNotification");
- NSDictionary *nameDictionary = [notification userInfo];
- NSString *respcode = [nameDictionary objectForKey:@"respcode"];
- if([respcode isEqualToString:@"1"]){
- // 支付成功,更新用户信息
- [self payDidFinish];
- }else{
- // 支付失败,
- [self setupAlertControllerWithTitle:@"微信支付结果" messge:@"本次支付未完成,您可以稍后重试!" confirm:@"好的"];
- }
- }