微信支付(微信支付的坑基本上都踩过一遍了)


项目中要用到支付宝支付和微信支付,先做了支付宝,本以为微信也很简单,看过文档之后又亲测了一遍,踩了好几个坑。。。顺便吐槽下微信的开发文档 再见

开始项目:

准备工作:

1、微信开放平台:https://open.weixin.qq.com/,注册账号,获取appid和密钥。
2、大家也可以下载下官方的demo。我当时下载的例子里的统一下单接口都是错的。
3、创建应用,此处注意填写应用的包名,和应用签名,应用签名可以用签名工具生成。签名工具在平台上都可以下得到。
4、微信支付是需要申请的,成功之后会有个商户id。

接口链接

URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

统一下单文档大家可以看看。

3、导入微信sdk

调用App支付

在研究过官方的demo之后,发现他只能获取到accessToken,但是到了获取prepayid就开始报错:打印了就会发现是:现在有错误返回{"errcode":268497023,"errmsg":"您已完成交易接口升级,老接口交易权限已关闭,请使用新接口进行交易。如有疑问请联系微信支付客服咨询"}--(很明显接口都没更新成最新的!!!不是最新的,不知道后来跟新了没有),为了保证安全的情况下,我们要从后台获取repayid。但是我们后台并没有写,所以,我下边讲的代码都是在客户端生成prepayid。

首先,需要你在开放平台上获取到的app_ID、密钥、商户账号


加上请求的参数通过统一下单的接口来获取会话标识,在return_code 和result_code都为SUCCESS的时候获取prepay_id(prepay_id我在客户端生成,有效时期24小时,用于后边吊起支付界面。)在这一步中我们还要生成签名并把它当作参数之一提交,许多时候都是签名的错误而难以生存prepay_id。下面的参数就是用来获取会话标识的。


private String genProductArgs() {
		StringBuffer xml = new StringBuffer();
		try {
			String nonceStr = genNonceStr();
			xml.append("");
            List
    
    
     
      packageParams = new LinkedList
     
     
      
      ();
			packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));	
			packageParams.add(new BasicNameValuePair("body", body));
			packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
			packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
			packageParams.add(new BasicNameValuePair("notify_url", notify_url));
			packageParams.add(new BasicNameValuePair("out_trade_no", outTradNo));
			packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1"));
			packageParams.add(new BasicNameValuePair("total_fee", total_fee));
			packageParams.add(new BasicNameValuePair("trade_type", "APP"));
			String sign = genPackageSign(packageParams);
			packageParams.add(new BasicNameValuePair("sign", sign));
			String xmlstring = toXml(packageParams);	
//			return new String(xmlstring.toString().getBytes(), "ISO8859-1");
			return xmlstring;
		} catch (Exception e) {
			Log.v(TAG, "genProductArgs fail, ex = " + e.getMessage());
			return null;
		}

	}
	
	/**
	 * 生成签名
	 */
	private String genPackageSign(List
      
      
       
        params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes())
				.toUpperCase(Locale.CHINA);
		Log.e("签名-->", packageSign);
		return packageSign;
	}
	
	
      
      
     
     
    
    

通过以上代码就完成了第一步,我们得到了prepay_id,现在就要吊起支付的界面,根据文档上给出的需要请求的参数,



empty
	private void genPayReq() {

		req.appId = Constants.APP_ID;
		req.partnerId = Constants.MCH_ID;
		req.prepayId = resultunifiedorder.get("prepay_id");
		req.packageValue = "Sign=WXPay";
		req.nonceStr = genNonceStr();
		req.timeStamp = String.valueOf(genTimeStamp());

		List
      
      
       
        signParams = new LinkedList
       
       
        
        ();
		signParams.add(new BasicNameValuePair("appid", req.appId));
		signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
		signParams.add(new BasicNameValuePair("package", req.packageValue));
		signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
		signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
		signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));

		req.sign = genAppSign(signParams);

		sb.append("sign\n" + req.sign + "\n\n");

		Log.v("orion-signParams-->", signParams.toString());
		
		sendPayReq();
		

	}
       
       
      
      

到这里支付就完成了一大半了,现在要处理的就是支付成功、失败之后的情况,和取消支付的处理。结果处理:

要在WXPayEntryActivity里处理!而这个文件就更神奇了,一定要放在指定的包下,你的包名.wxapi,你的包名.wxapi,你的包名.wxapi,重要的事情说三遍,不要问我为什么,微信就是这么搞回调。

public void onResp(BaseResp resp) {




if(resp.errCode==-1){
setJieguowei(resp.errCode);
Toast.makeText(WXPayEntryActivity.this, "支付错误", Toast.LENGTH_SHORT).show();
WXPayEntryActivity.this.finish();
}
if(resp.errCode==0){

//后续处理
Toast.makeText(WXPayEntryActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
WXPayEntryActivity.this.finish();
}
if(resp.errCode==-2){
Toast.makeText(WXPayEntryActivity.this, "用户取消", Toast.LENGTH_SHORT).show();
WXPayEntryActivity.this.finish();
}


}

下面是微信支付的整个工具类,网络请求的封装和MD5的加密工具都没贴出,我会发在下载的文件夹里。

emptypublic class WxPayUtile {
	private Context context;
	PayReq req;
	final IWXAPI msgApi;
	Map
     
     
      
       resultunifiedorder;
	StringBuffer sb;
	private String total_fee;
	private String notify_url;
	private String body;
	private String outTradNo;

	private static final String TAG = "123";


	/**
	 *
	 *   用法:WxPayUtile wxPayUtile = new WxPayUtile(getActivity(),"1","服务器回调地址","产品名称","订单号");
	           wxPayUtile.doPay();
	 *
	 * @param context   上下文
	 * @param total_fee   价格
	 * @param notify_url   服务器回调地址
	 * @param body   商品名称或其他
	 * @param outTradNo  定单号
	 */
	public WxPayUtile(Context context, String total_fee, String notify_url,
			String body, String outTradNo) {
		super();
		msgApi = WXAPIFactory.createWXAPI(context, null);
		req = new PayReq();
		msgApi.registerApp(Constants.APP_ID);
		sb = new StringBuffer();
		this.context = context;
		this.total_fee = total_fee;
		this.notify_url = notify_url;
		this.body = body;
		this.outTradNo = outTradNo;
	}

	public static WxPayUtile getInstance(Context context, String total_fee,
			String notify_url, String body, String outTradNo) {

		return new WxPayUtile(context, total_fee, notify_url, body, outTradNo);
	}

	public void doPay() {

		GetPrepayIdTask getPrepayId = new GetPrepayIdTask();
		getPrepayId.execute();
	}

	/**
	 * 生成签名
	 */
	private String genPackageSign(List
      
      
       
        params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes())
				.toUpperCase(Locale.CHINA);
		Log.e("签名-->", packageSign);
		return packageSign;
	}

	private String genAppSign(List
       
       
        
         params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);

		this.sb.append("sign str\n" + sb.toString() + "\n\n");
		String appSign = MD5.getMessageDigest(sb.toString().getBytes())
				.toUpperCase();
		Log.e("app签名-->", appSign);
		return appSign;
	}

	private String toXml(List
        
        
         
          params) {
		StringBuilder sb = new StringBuilder();
		sb.append("
         
         
           "); for (int i = 0; i < params.size(); i++) { sb.append("<" + params.get(i).getName() + ">"); sb.append(params.get(i).getValue()); sb.append(" 
          "); } sb.append(" 
         ");

		Log.e("orion-sb--->", sb.toString());
		return sb.toString();
	}

	private class GetPrepayIdTask extends
			AsyncTask
         
         
           > { @Override protected void onPreExecute() { Toast.makeText(context, "正在准备支付", Toast.LENGTH_SHORT).show(); } @Override protected void onPostExecute(Map 
          
            result) { sb.append("prepay_id\n" + result.get("prepay_id") + "\n\n"); resultunifiedorder = result; // Log.e("orion-result_code-->", result.get("result_code")); if (result.get("result_code").equals("SUCCESS")) { Log.v("orion-result_code-->", "IS SUCCESS!"); // Toast.makeText(context, "成功支付123654", Toast.LENGTH_SHORT).show(); genPayReq(); } if (result.get("result_code").equals("FAIL")) { String miaoshuString=result.get("err_code_des"); Toast.makeText(context, miaoshuString, Toast.LENGTH_SHORT).show(); } } @Override protected void onCancelled() { super.onCancelled(); Toast.makeText(context, "quxiao", Toast.LENGTH_SHORT).show(); } @Override protected Map 
           
             doInBackground(Void... params) { String url = String .format("https://api.mch.weixin.qq.com/pay/unifiedorder"); String entity = genProductArgs(); Log.v("entity-->", entity); byte[] buf = HttpWxUtile.httpPost(url, entity); String content = new String(buf); Log.v("content-->", content); Map 
            
              xml = decodeXml(content); return xml; } } public Map 
             
               decodeXml(String content) { try { Map 
              
                xml = new HashMap 
               
                 (); XmlPullParser parser = Xml.newPullParser(); parser.setInput(new StringReader(content)); int event = parser.getEventType(); while (event != XmlPullParser.END_DOCUMENT) { String nodeName = parser.getName(); switch (event) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: if ("xml".equals(nodeName) == false) { // 实例化student对象 xml.put(nodeName, parser.nextText()); } break; case XmlPullParser.END_TAG: break; } event = parser.next(); } return xml; } catch (Exception e) { Log.v("orion-e--->", e.toString()); } return null; } private String genNonceStr() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)) .getBytes()); } private long genTimeStamp() { return System.currentTimeMillis() / 1000; } // private String genProductArgs() { StringBuffer xml = new StringBuffer(); try { String nonceStr = genNonceStr(); xml.append(""); List 
                
                  packageParams = new LinkedList 
                 
                   (); packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID)); packageParams.add(new BasicNameValuePair("body", body)); packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); packageParams.add(new BasicNameValuePair("nonce_str", nonceStr)); packageParams.add(new BasicNameValuePair("notify_url", notify_url)); packageParams.add(new BasicNameValuePair("out_trade_no", outTradNo)); packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1")); packageParams.add(new BasicNameValuePair("total_fee", total_fee)); packageParams.add(new BasicNameValuePair("trade_type", "APP")); String sign = genPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); String xmlstring = toXml(packageParams); // return new String(xmlstring.toString().getBytes(), "ISO8859-1"); return xmlstring; } catch (Exception e) { Log.v(TAG, "genProductArgs fail, ex = " + e.getMessage()); return null; } } private void genPayReq() { req.appId = Constants.APP_ID; req.partnerId = Constants.MCH_ID; req.prepayId = resultunifiedorder.get("prepay_id"); req.packageValue = "Sign=WXPay"; req.nonceStr = genNonceStr(); req.timeStamp = String.valueOf(genTimeStamp()); List 
                  
                    signParams = new LinkedList 
                   
                     (); signParams.add(new BasicNameValuePair("appid", req.appId)); signParams.add(new BasicNameValuePair("noncestr", req.nonceStr)); signParams.add(new BasicNameValuePair("package", req.packageValue)); signParams.add(new BasicNameValuePair("partnerid", req.partnerId)); signParams.add(new BasicNameValuePair("prepayid", req.prepayId)); signParams.add(new BasicNameValuePair("timestamp", req.timeStamp)); req.sign = genAppSign(signParams); sb.append("sign\n" + req.sign + "\n\n"); Log.v("orion-signParams-->", signParams.toString()); sendPayReq(); } private void sendPayReq() { msgApi.registerApp(Constants.APP_ID); msgApi.sendReq(req); // msgApi.handleIntent(arg0, arg1) } } 
                    
                   
                  
                 
                
               
              
             
            
           
         
        
        
       
       
      
      
     
     

签名错误:解决办法

1、我们要在打包的状态下测试。
2、检查包名是否正确,平台上的包名和应用的包名是否一致
3、打包之后再用签名工具生成一次签名,(我就是出了这个鬼。同样的签名文件打包两次的签名竟然不一样,当然后面就都一样了)

工具下载地址:http://download.csdn.net/detail/heiya0409/9642251









  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值