您的位置:首页 > 移动开发 > 微信开发

安卓微信支付步骤简述

2015-08-06 14:43 204 查看
前段时间为公司商城加上了微信支付,中间各种困恼。今天因为改点东西,重拾了出来,就顺便给出一个简单的步骤吧。

一: 定义API, 用于调用API生成预支付订单等

private IWXAPI msgApi;

protected void onCreate(Bundle savedInstanceState) {

msgApi = WXAPIFactory.createWXAPI(BrowserActivity.this, null);

}

二:拿到订单号,价格(记得微信支付单位为1分哦),调用API生成预支付订单

msgApi.registerApp(UtilData.APP_ID);

GetPrepayIdTask getPrepayId = new GetPrepayIdTask(p_order, p_desc, testPrice);

getPrepayId.execute();

三:生成预支付订单后,拿到APP_ID, 预支付订单号等信息封装Post,

req2 = WeiXinGenerate.genPayReq(prepayId);

// Post the pay info

/*关键代码2:提交支付信息*/

msgApi.registerApp(UtilData.APP_ID);

msgApi.sendReq(req2);

四:定义WXPayEntryActivity,(必须是你申请的签名下的wxapi报下。如:com.XX.XX.wxapi,其中comm.XX.XX就是你申请的包)

public void onResp(BaseResp resp) {

if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {

PayResp response = (PayResp)resp;

String prePayId = response.prepayId;

switch(resp.errCode){

case 0:

//支付成功 (注,这时候返回的状态并不一定完全正确,处理前最后再调用微信API查询一下result)

break;

case -1:

//支付失败

break;

case -2:

// 支付取消

break;

}

}

}

==============好了关键要调用的步骤,就这几步。接下来补充各种类和方法====================

一: 生成预订单时调用的GetPrepayIdTask类

另注: UtilData.WEIXIN_API="https://api.mch.weixin.qq.com/pay/unifiedorder";

UtilData.APP_ID = 你申请的APP_ID

private class GetPrepayIdTask extends AsyncTask<Void, Void, Map<String,String>> {

private String payOrderId;

private String productDesc;

private int productPrice;

public GetPrepayIdTask(String orderId, String desc, int price){

payOrderId = orderId;

productDesc = desc;

productPrice = price;

}



@Override

protected void onPreExecute() {

dialog = ProgressDialog.show(BrowserActivity.this, "", ""));

}

@Override

protected void onPostExecute(Map<String,String> result) {

if (dialog != null) {

dialog.dismiss();

}



if (result.get("return_code").equalsIgnoreCase("FAIL")) {

// 调用失败,可以给出提示消息

dialog = ProgressDialog.show(BrowserActivity.this, "",""));

dialog.dismiss();

return;

}

String resultCode = result.get("result_code");

if (resultCode.equalsIgnoreCase("SUCCESS")) {

// 成功生成预支付订单

String prepayId = result.get("prepay_id");



UtilData.LAST_PREPAYID = prepayId;

UtilData.LAST_ORDER = payOrderId;



PayReq req2 = new PayReq();



// Generate the pay request

req2 = WeiXinGenerate.genPayReq(prepayId);



// Post the pay info

/*关键代码2:提交支付信息*/

msgApi.registerApp(UtilData.APP_ID);

msgApi.sendReq(req2);



} else if (resultCode.equalsIgnoreCase("FAIL")) {

// 错误处理

String errCode = result.get("err_code");

return;

}



}



@Override

protected Map<String,String> doInBackground(Void... params) {

/*关键代码1:生成预支付订单*/

String entity = WeiXinGenerate.genProductArgs(payOrderId, productDesc, productPrice, UtilData.SHOP_LINK);

byte[] buf = Util.httpPost(UtilData.WEIXIN_API, entity);

String content = new String(buf);

Map<String,String> xml= WeiXinGenerate.decodeXml(content);

return xml;

}

}

二:封装和解析数据的WeiXinGenerate.(大多数来自微信demo中方法的封装). 如下。注:APP_ID, PARTNER_ID,API_KEY为你申请的几个数据。

public class WeiXinGenerate {

/**

* Generate parameters for prepay

* @param description

* @param price

* @return

*/

public static String genProductArgs(String orderId, String description, int price, String notifyUrl) {

try {

String nonceStr = genNonceStr();

List<NameValuePair> packageParams = new LinkedList<NameValuePair>();

packageParams.add(new BasicNameValuePair("appid", UtilData.APP_ID));

packageParams.add(new BasicNameValuePair("body", description));

packageParams.add(new BasicNameValuePair("mch_id", UtilData.PARTNER_ID));

packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));

packageParams.add(new BasicNameValuePair("notify_url", notifyUrl));

String outTradeNo = MyMD5.getMessageDigest(orderId.getBytes());

packageParams.add(new BasicNameValuePair("out_trade_no", outTradeNo));//genOutTradNo()));//orderId));//

packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1"));

packageParams.add(new BasicNameValuePair("total_fee", String.valueOf(price)));

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.getBytes(), "ISO8859-1");

} catch (Exception e) {

return null;

}

}

/**

* Get map object

* @param content

* @return

*/

public static 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) {

Log.e("orion-exception",e.toString());

}

return null;

}



/**

* Generate parameters for pay

* @param prepayId

* @return

*/

public static PayReq genPayReq(String prepayId) {

PayReq req = new PayReq();

req.appId = UtilData.APP_ID;

req.partnerId = UtilData.PARTNER_ID;

req.prepayId = prepayId;

req.packageValue = "Sign=WXPay";

req.nonceStr = genNonceStr();

req.timeStamp = String.valueOf(genTimeStamp());

List<NameValuePair> signParams = new LinkedList<NameValuePair>();

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);



return req;

}



/**

* For order query and close

* @param orderId

* @return

*/

public static String genQueryReq(String orderId) {

try {

String nonceStr = genNonceStr();

List<NameValuePair> packageParams = new LinkedList<NameValuePair>();

packageParams.add(new BasicNameValuePair("appid", UtilData.APP_ID));

packageParams.add(new BasicNameValuePair("mch_id", UtilData.PARTNER_ID));

packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));

String outTradeNo = MyMD5.getMessageDigest(orderId.getBytes());

packageParams.add(new BasicNameValuePair("out_trade_no", outTradeNo));

String sign = genPackageSign(packageParams);

packageParams.add(new BasicNameValuePair("sign", sign));

String xmlstring =toXml(packageParams);

return new String(xmlstring.getBytes(), "ISO8859-1");

} catch (Exception e) {

return null;

}

}



/**

* For order query and close

* @param orderId

* @return

*/

public static String genTrackeReq(String orderId) {

try {

String nonceStr = genNonceStr();

List<NameValuePair> packageParams = new LinkedList<NameValuePair>();

packageParams.add(new BasicNameValuePair("appid", UtilData.APP_ID));

packageParams.add(new BasicNameValuePair("mch_id", UtilData.PARTNER_ID));

packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));

String outTradeNo = MyMD5.getMessageDigest(orderId.getBytes());

packageParams.add(new BasicNameValuePair("out_trade_no", outTradeNo));

packageParams.add(new BasicNameValuePair("out_refund_no", outTradeNo));

packageParams.add(new BasicNameValuePair("total_fee", String.valueOf(1)));

packageParams.add(new BasicNameValuePair("refund_fee", String.valueOf(1)));

String sign = genPackageSign(packageParams);

packageParams.add(new BasicNameValuePair("sign", sign));

String xmlstring =toXml(packageParams);

return new String(xmlstring.getBytes(), "ISO8859-1");

} catch (Exception e) {

return null;

}

}



private static String toXml(List<NameValuePair> params) {

StringBuilder sb = new StringBuilder();

sb.append("<xml>");

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("</xml>");

try {

return new String(sb.toString().getBytes(), "ISO8859-1");

} catch (UnsupportedEncodingException e) {

return sb.toString();

}

//return sb.toString();

}



private static String genPackageSign(List<NameValuePair> 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(UtilData.API_KEY);



String packageSign = MyMD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();

return packageSign;

}



private static String genNonceStr() {

Random random = new Random();

return MyMD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());

}



private static long genTimeStamp() {

return System.currentTimeMillis() / 1000;

}



private static String genAppSign(List<NameValuePair> 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(UtilData.API_KEY);

String appSign = MyMD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();

return appSign;

}

}

三. UtilData类定义的是各种值

public class UtilData {

// Account info

protected static final String APP_ID = "";

protected static final String PARTNER_ID = "";

protected static final String API_KEY="";

// Wei xin api

protected static String WEIXIN_API="https://api.mch.weixin.qq.com/pay/unifiedorder";

protected static String WEIXIN_QUERY="https://api.mch.weixin.qq.com/pay/orderquery";

protected static String WEIXIN_CLOSE="https://api.mch.weixin.qq.com/pay/closeorder";

}

四:另外的工具类Util,MD5Util, MyMD5等其实都是微信demo里给的,没有什么需要预览的。但是不能给附件,只好直接贴出来了

public class Util {



private static final String TAG = "SDK_Sample.Util";



public static byte[] httpGet(final String url) {

if (url == null || url.length() == 0) {

Log.e(TAG, "httpGet, url is null");

return null;

}

HttpClient httpClient = getNewHttpClient();

HttpGet httpGet = new HttpGet(url);

try {

HttpResponse resp = httpClient.execute(httpGet);

if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {

Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());

return null;

}

return EntityUtils.toByteArray(resp.getEntity());

} catch (Exception e) {

Log.e(TAG, "httpGet exception, e = " + e.getMessage());

e.printStackTrace();

return null;

}

}



public static byte[] httpPost(String url, String entity) {

if (url == null || url.length() == 0) {

Log.e(TAG, "httpPost, url is null");

return null;

}



HttpClient httpClient = getNewHttpClient();



HttpPost httpPost = new HttpPost(url);



try {

httpPost.setEntity(new StringEntity(entity));

httpPost.setHeader("Accept", "application/json");

httpPost.setHeader("Content-type", "application/json");



HttpResponse resp = httpClient.execute(httpPost);

if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {

Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());

return null;

}

return EntityUtils.toByteArray(resp.getEntity());

} catch (Exception e) {

Log.e(TAG, "httpPost exception, e = " + e.getMessage());

e.printStackTrace();

return null;

}

}



private static class SSLSocketFactoryEx extends SSLSocketFactory {



SSLContext sslContext = SSLContext.getInstance("TLS");



public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {

super(truststore);



TrustManager tm = new X509TrustManager() {



public X509Certificate[] getAcceptedIssuers() {

return null;

}



@Override

public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {

}

@Override

public void checkServerTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {

}

};



sslContext.init(null, new TrustManager[] { tm }, null);

}



@Override

public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {

return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);

}

@Override

public Socket createSocket() throws IOException {

return sslContext.getSocketFactory().createSocket();

}

}

private static HttpClient getNewHttpClient() {

try {

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

trustStore.load(null, null);

SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);

sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

HttpParams params = new BasicHttpParams();

HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);

HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

SchemeRegistry registry = new SchemeRegistry();

registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

registry.register(new Scheme("https", sf, 443));

ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

return new DefaultHttpClient(ccm, params);

} catch (Exception e) {

return new DefaultHttpClient();

}

}



}

public class MyMD5 {



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;

}

}

}

=============================应该没有遗漏了,接下来补充几个遇到的问题========================================

一:关于APP_Key

之前以为是AppSecret,结果发现并不是,就是APP_Key同样是32位数字。

二:取消支付,再支付OUT_TRADE_NO_USED

开始以为是要调用close接口,发现调用只好,再提起支付又是“ORDERCLOSED” ->_->。只好先close再后台生成新的订单号支付, 话说有时候却是可以不改订单号,直接再次提交的

三:关于notify_url

测试时也要给外网的notify_url哦,不然调用不到的。。死在这里n久。。。

四:return_code与result_code。

也许并不是每个人同我一样粗心,return_code=success仅表示返回成功,result_code=success才表示业务成功。——然后,notify_url对应的接口里,判断以上两个还没完,trade_state=success才表示成功

=========over 有问题再补充
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: