开始项目:
准备工作:
接口链接
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) } }
签名错误:解决办法
工具下载地址:http://download.csdn.net/detail/heiya0409/9642251