1.拼接商品的信息
List packageParams = new LinkedList();
packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));
packageParams.add(new BasicNameValuePair("body", orderNo+""));
packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
packageParams.add(new BasicNameValuePair("notify_url",
Urls.ROOT + "appPay/wechatPaySuccess/" + orderNos + ".htm"));
// 输出订单号
packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo(orderNos)));
// 订单价格(此处为模拟的固定值)
long total_fee = (long) (1);
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));
在拼接商品信息的时候调起支付可能会提示签名错误的问题,这个问题一般出现有可能有以下几种情况:
1.微信应用的appid错误
2.商户的商户id错误
3.appkey错误
4.参数拼接的顺序不对
对于这四个问题解决的办法分别如下:
1.微信管理平台地址 进入微信管理平台地址登陆之后查看应用的AppID另外要注意Android要填写应用签名的时候字符应该是小写的且无:符号的32位MD5值,Apk有可能是由公司的keystore文件打包出来的,或者是由个人的keystore文件打包出来的,微信管理平台中填写的MD5签名如果是公司的keystore打包出来的,那么如果想正常调起支付,测试的时候就需要用公司的keystore打包进行安装测试,方可调起支付。
2.微信支付申请成功之后微信会转发一份邮件到邮箱这个里面有商户id。
3.根据邮件中的微信商户平台登录的账号及密码到微信商户登陆地址中登陆,集成微信支付里面需要自己主动去设置一个API密钥具体操作进入在账户设置-API安全-设置密钥,这个密钥为32个字符,只允许输入数字和英文大小写字母的组合,可以到32位密钥生成链接地址 去随机生成一个密钥并记录下这个密钥前端需要用到后台同样需要用到这个东西
4.有可能你前面三步都没有问题,但是打印的log却一直说签名错误,当出现这个问题的时候你可以到微信支付参数验签地址 去把参数传上去来查看MD5签名 在调试软件的时候你也需要打印这个签名
/**
* 生成签名
*/
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();
Log.e("PackageSign", packageSign);
return packageSign;
}
这两个签名不一样,1种可能是签名算法不一样,一种可能是参数不一样,在验签网址中会将参数打印出来因此可以使用连接商户的key这个str来直接带入到
String packageSign = MD5.getMessageDigest(sb.toString().getBytes())
.toUpperCase();
中 来获得签名,如果这个打印的签名与验签网址中的签名一样那么签名的算法是没有问题的。第二种可能参数不一样,看到图片中所拼接的参数顺序,你所传的参数顺序应该是与网址中参数顺序是一模一样的,不然生成的签名是不一样的,因此就会报签名错误。
另外贴一下代码:
package com.bm.matrip.wechatpay;
import java.io.StringReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.xmlpull.v1.XmlPullParser;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.provider.DocumentsContract.Root;
import android.util.Log;
import android.util.Xml;
import com.bm.matrip.constants.Urls;
import com.tencent.mm.sdk.modelpay.PayReq;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
/**
* 微信支付
*/
public class GetPrepayIdTask extends AsyncTask> {
private StringBuffer sb = new StringBuffer();
private Map resultunifiedorder;
private PayReq req = new PayReq();
private IWXAPI msgApi;
private Context c;
private double price;
/**
* 订单号
*/
private String orderNo;
/**
* 多个订单
*/
private String orderNos;
public GetPrepayIdTask(Context c, double price, String orderNo, String orderNos) {
msgApi = WXAPIFactory.createWXAPI(c, null);
this.c = c;
this.price = price;
this.orderNo = orderNo;
this.orderNos = orderNos;
}
private ProgressDialog dialog;
@Override
protected void onPreExecute() {
dialog = ProgressDialog.show(c, "弹窗提示", "正在加载");
}
@Override
protected void onPostExecute(Map result) {
if (dialog != null) {
dialog.dismiss();
}
sb.append("prepay_id\n" + result.get("prepay_id") + "\n\n");
resultunifiedorder = result;
genPayReq();
msgApi.registerApp(Constants.APP_ID);
msgApi.sendReq(req);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected Map doInBackground(Void... params) {
String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
String entity = genProductArgs();
byte[] buf = Util.httpPost(url, entity);
String content = new String(buf);
Log.e("orion", content);
Map xml = decodeXml(content);
return xml;
}
private void genPayReq() {
req.appId = Constants.APP_ID;
req.partnerId = Constants.MCH_ID;
//req.prepayId=Constants.API_KEY;
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("appkey", Constants.API_KEY));
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.e("orion", signParams.toString());
// req.appId = Constants.APP_ID;
// req.partnerId = Constants.MCH_ID;
// req.prepayId="wx20150928191247ec2bfe36120916857122";
// req.packageValue = "Sign=WXPay";
// req.nonceStr="lPLaOjotrEy9MYx3";
// req.sign="10DD9C41A6857B4C4AEA98E24605925C";
// req.timeStamp="1443437278";
}
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("orionAppSign", appSign);
return appSign;
}
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", orderNo+""));
packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
packageParams.add(new BasicNameValuePair("notify_url",
Urls.ROOT + "appPay/wechatPaySuccess/" + orderNos + ".htm"));
// 订单
packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo(orderNos)));
// 订单价格
long total_fee = (long) (1);
// 订单
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 xmlstring;
} catch (Exception e) {
// Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage());
return null;
}
}
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.e("orion", 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 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();
Log.e("orionStringBuilder", sb.toString());
Log.e("orionAppMd5", packageSign);
return packageSign;
}
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("" + params.get(i).getName() + ">");
}
sb.append("");
Log.e("orion", sb.toString());
return sb.toString();
}
/**
* 订单号信息
*
* @return
*/
private String genOutTradNo(String orderNos) {
// Random random = new Random();
return MD5.getMessageDigest(String.valueOf(orderNos).getBytes());
}
}