1.阅读文档,配置信息
按照以上要求配置信息得到商户Id,在商户平台生成的密钥,AppId,AppSecret。
- 导入微信支付SDK,加入所需权限。
一般将这些信息写在一个常量类里面方便维护,如下:
/**
* 微信支付必备参数
*/
public calss WeChatConstants{
public static final String WECHAT_APP_ID = "在微信开发平台生成的AppId";
public static final String WECHAT_APP_SECRET = "在微信开发平台生成的AppSecret";
public static final String WECHAT_PARTNER_ID = "商户ID";
public static final String WECHAT_PARTNER_KEY = "在商户平台生成的密钥";
public static final String WECHAT_RESULT_NOTIFY = "微信回调服务器接口地址";
public static final String WECHAT_UNIFIED_ORDER = "微信统一下单接口地址";
}
可根据项目需求替换以上参数值供自己使用。
- 自定义微信支付model ,方便参数设置。
/**
* 描述 :只需要定义 key, value 即可。
*/
public class WeChatPayBean<K, V> {
private K key;
private V value;
public WeChatPayBean(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
2.开始支付
首先商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付。也就是说服务端调用该接口从微信那边获得一个与支付订单号。
- 使用AsyncTask获取订单信息
/**
* 微信支付统一下单接口地址
*/
https://api.mch.weixin.qq.com/pay/unifiedorder
private Map<String, String> mResult ;// 定义一个Map集合,用来接收得到的订单信息
public void getPrepayId(final Activity activity, final IWXAPI mApi) {
Toast.makeTextactivity, "获取订单中...", Toast.LENGTH_SHORT).show();
new AsyncTask<Void, Void, Map<String, String>>() {
@Override
protected void onPostExecute(Map<String, String> result) {
if (result != null) {
mResult = result;
getPayReq(mApi);
}
}
@Override
protected Map<String, String> doInBackground(Void... voids) {
String url = String.format(WeChatConstants.WECHAT_UNIFIED_ORDER);// 统一下单接口地址
byte[] buf = HttpUtils.httpPost(url, getProductArgs());// HttpUtils.httpPost(); 为post请求
try {
return decodeXml(new String(buf));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
- 申请调起支付
private void getPayReq(IWXAPI mApi) {
PayReq mPayReq = new PayReq();
mPayReq.appId = WeChatConstants.WECHAT_APP_ID;// AppId
mPayReq.partnerId = WeChatConstants.WECHAT_PARTNER_ID;// 微信支付分配的商户号
mPayReq.prepayId = mResult.get("prepay_id");// 支付订单Id
mPayReq.packageValue = "Sign=WXPay";// 扩展字段,暂填写固定值Sign=WXPay
mPayReq.nonceStr = getNonceString();// 随机数字符串
mPayReq.timeStamp = String.valueOf(getTimeStamp());// 时间戳
List<WeChatPayBean> signParams = new AraaryList<WeChatPayBean>();
signParams.add(new WeChatPayBean("appid", mPayReq.appId));
signParams.add(new WeChatPayBean("noncestr", mPayReq.nonceStr));
signParams.add(new WeChatPayBean("package", mPayReq.packageValue));
signParams.add(new WeChatPayBean("partnerid", mPayReq.partnerId));
signParams.add(new WeChatPayBean("prepayid", mPayReq.prepayId));
signParams.add(new WeChatPayBean("timestamp", mPayReq.timeStamp));
mPayReq.sign = genAppSign(signParams);
mApi.sendReq(mPayReq);
}
- 统一下单请求参数设置(这里只设置必要参数):
/**
* 根据微信官方支付文档设置需要的参数
*/
private String getProductArgs() {
StringBuffer xml = new StringBuffer();
try {
String nonceString = getNonceString();// 获取随机字符串,方法在本贴下面给出
String bodyString = "xxx充值";// 商品描述交易描述。例如:腾讯充值中心-QQ会员充值
xml.append("</xml>");
List<WeChatPayBean> packageParams = new ArrayList<WeChatPayBean>();
packageParams.add(new WeChatPayBean("appid", WeChatConstants.WECHAT_APP_ID));// AppId
packageParams.add(new WeChatPayBean("body", bodyString));
packageParams.add(new WeChatPayBean("mch_id", WeChatConstants.WECHAT_PARTNER_ID));// 微信支付分配的商户号
packageParams.add(new WeChatPayBean("nonce_str", nonceString));// 随机字符串
packageParams.add(new WeChatPayBean("notify_url", WeChatConstants.WECHAT_RESULT_NOTIFY ));// 微信回调服务端地址
packageParams.add(new WeChatPayBean("out_trade_no", "支付订单号"));// 服务端返回的支付订单号
packageParams.add(new WeChatPayBean("spbill_create_ip", "设备IP"));// 设备IP,当前设备IP,默认为“WEB”
packageParams.add(new WeChatPayBean("total_fee", "订单金额"));// 订单总金额,单位为分。根据商户商品价格定义,此处需自行设置
packageParams.add(new WeChatPayBean("trade_type", "APP"));// 交易类型
packageParams.add(new WeChatPayBean("sign", getAppSign(packageParams)));// 签名,方法在本贴下面
String xmls = toXml(packageParams);
return new String(xmls.toString().getBytes(), "ISO8859-1");// 设置编码格式
} catch (Exception e) {
return null;
}
}
- 得到一个随机字符串
private String getNonceString() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
- 微信支付MD5加密工具类
public class MD5 {
private MD5() { }
public final static String getMessageDigest(byte[] buffer) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
}
- 签名( 签名规范)
private String getAppSign(List<PayBean> params) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
sb.append(params.get(i).getKey());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append(WeChatConstants.WECHAT_PARTNER_KEY);// 商户平台生成的密钥
String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return appSign;
}
- 时间戳
private long getTimeStamp() {
SimpleDateFormat time = new SimpleDateFormat("yyyyMMddkkmmss");
return Long.valueOf(time.format(new Date()));
}
- 生成XML
private String toXml(List<WeChatPayBean> params) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
for (int i = 0; i < params.size(); i++) {
sb.append("<" + params.get(i).getKey() + ">");
sb.append(params.get(i).getValue());
sb.append("</" + params.get(i).getKey() + ">");
}
sb.append("</xml>");
return sb.toString();
}
- 解析XML
public Map<String, String> decodeXml(String content) {
try {
Map<String, String> xml = new HashMap<String, String>();
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) {
xml.put(nodeName, parser.nextText());
}
break;
case XmlPullParser.END_TAG:
break;
}
event = parser.next();
}
return xml;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
3.微信支付扣款成功后,微信会通过回调告诉商户后台扣款成功,此时我们需要调用后台接口查询订单状态。
按照以上要求配置信息得到商户Id,在商户平台生成的密钥,AppId,AppSecret。
- 导入微信支付SDK,加入所需权限。
一般将这些信息写在一个常量类里面方便维护,如下:
/**
* 微信支付必备参数
*/
public calss WeChatConstants{
public static final String WECHAT_APP_ID = "在微信开发平台生成的AppId";
public static final String WECHAT_APP_SECRET = "在微信开发平台生成的AppSecret";
public static final String WECHAT_PARTNER_ID = "商户ID";
public static final String WECHAT_PARTNER_KEY = "在商户平台生成的密钥";
public static final String WECHAT_RESULT_NOTIFY = "微信回调服务器接口地址";
public static final String WECHAT_UNIFIED_ORDER = "微信统一下单接口地址";
}
可根据项目需求替换以上参数值供自己使用。
- 自定义微信支付model ,方便参数设置。
/**
* 描述 :只需要定义 key, value 即可。
*/
public class WeChatPayBean<K, V> {
private K key;
private V value;
public WeChatPayBean(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
2.开始支付
首先商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付。也就是说服务端调用该接口从微信那边获得一个与支付订单号。
- 使用AsyncTask获取订单信息
/**
* 微信支付统一下单接口地址
*/
https://api.mch.weixin.qq.com/pay/unifiedorder
private Map<String, String> mResult ;// 定义一个Map集合,用来接收得到的订单信息
public void getPrepayId(final Activity activity, final IWXAPI mApi) {
Toast.makeTextactivity, "获取订单中...", Toast.LENGTH_SHORT).show();
new AsyncTask<Void, Void, Map<String, String>>() {
@Override
protected void onPostExecute(Map<String, String> result) {
if (result != null) {
mResult = result;
getPayReq(mApi);
}
}
@Override
protected Map<String, String> doInBackground(Void... voids) {
String url = String.format(WeChatConstants.WECHAT_UNIFIED_ORDER);// 统一下单接口地址
byte[] buf = HttpUtils.httpPost(url, getProductArgs());// HttpUtils.httpPost(); 为post请求
try {
return decodeXml(new String(buf));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
- 申请调起支付
private void getPayReq(IWXAPI mApi) {
PayReq mPayReq = new PayReq();
mPayReq.appId = WeChatConstants.WECHAT_APP_ID;// AppId
mPayReq.partnerId = WeChatConstants.WECHAT_PARTNER_ID;// 微信支付分配的商户号
mPayReq.prepayId = mResult.get("prepay_id");// 支付订单Id
mPayReq.packageValue = "Sign=WXPay";// 扩展字段,暂填写固定值Sign=WXPay
mPayReq.nonceStr = getNonceString();// 随机数字符串
mPayReq.timeStamp = String.valueOf(getTimeStamp());// 时间戳
List<WeChatPayBean> signParams = new AraaryList<WeChatPayBean>();
signParams.add(new WeChatPayBean("appid", mPayReq.appId));
signParams.add(new WeChatPayBean("noncestr", mPayReq.nonceStr));
signParams.add(new WeChatPayBean("package", mPayReq.packageValue));
signParams.add(new WeChatPayBean("partnerid", mPayReq.partnerId));
signParams.add(new WeChatPayBean("prepayid", mPayReq.prepayId));
signParams.add(new WeChatPayBean("timestamp", mPayReq.timeStamp));
mPayReq.sign = genAppSign(signParams);
mApi.sendReq(mPayReq);
}
- 统一下单请求参数设置(这里只设置必要参数):
/**
* 根据微信官方支付文档设置需要的参数
*/
private String getProductArgs() {
StringBuffer xml = new StringBuffer();
try {
String nonceString = getNonceString();// 获取随机字符串,方法在本贴下面给出
String bodyString = "xxx充值";// 商品描述交易描述。例如:腾讯充值中心-QQ会员充值
xml.append("</xml>");
List<WeChatPayBean> packageParams = new ArrayList<WeChatPayBean>();
packageParams.add(new WeChatPayBean("appid", WeChatConstants.WECHAT_APP_ID));// AppId
packageParams.add(new WeChatPayBean("body", bodyString));
packageParams.add(new WeChatPayBean("mch_id", WeChatConstants.WECHAT_PARTNER_ID));// 微信支付分配的商户号
packageParams.add(new WeChatPayBean("nonce_str", nonceString));// 随机字符串
packageParams.add(new WeChatPayBean("notify_url", WeChatConstants.WECHAT_RESULT_NOTIFY ));// 微信回调服务端地址
packageParams.add(new WeChatPayBean("out_trade_no", "支付订单号"));// 服务端返回的支付订单号
packageParams.add(new WeChatPayBean("spbill_create_ip", "设备IP"));// 设备IP,当前设备IP,默认为“WEB”
packageParams.add(new WeChatPayBean("total_fee", "订单金额"));// 订单总金额,单位为分。根据商户商品价格定义,此处需自行设置
packageParams.add(new WeChatPayBean("trade_type", "APP"));// 交易类型
packageParams.add(new WeChatPayBean("sign", getAppSign(packageParams)));// 签名,方法在本贴下面
String xmls = toXml(packageParams);
return new String(xmls.toString().getBytes(), "ISO8859-1");// 设置编码格式
} catch (Exception e) {
return null;
}
}
- 得到一个随机字符串
private String getNonceString() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
- 微信支付MD5加密工具类
public class MD5 {
private MD5() { }
public final static String getMessageDigest(byte[] buffer) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
}
- 签名( 签名规范)
private String getAppSign(List<PayBean> params) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
sb.append(params.get(i).getKey());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append(WeChatConstants.WECHAT_PARTNER_KEY);// 商户平台生成的密钥
String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return appSign;
}
- 时间戳
private long getTimeStamp() {
SimpleDateFormat time = new SimpleDateFormat("yyyyMMddkkmmss");
return Long.valueOf(time.format(new Date()));
}
- 生成XML
private String toXml(List<WeChatPayBean> params) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
for (int i = 0; i < params.size(); i++) {
sb.append("<" + params.get(i).getKey() + ">");
sb.append(params.get(i).getValue());
sb.append("</" + params.get(i).getKey() + ">");
}
sb.append("</xml>");
return sb.toString();
}
- 解析XML
public Map<String, String> decodeXml(String content) {
try {
Map<String, String> xml = new HashMap<String, String>();
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) {
xml.put(nodeName, parser.nextText());
}
break;
case XmlPullParser.END_TAG:
break;
}
event = parser.next();
}
return xml;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}