android 项目集成 微信支付
1.需要的常量值
public class Constant { /** 微信中用到的常量值 */ public static final class WX_CONSTANT { /** 微信支付 APP_ID */ public static final String APP_ID = "xxx"; /** 微信支付 商户号 */ public static final String MCH_ID = "xxx"; /** 微信支付 API密钥 */ public static final String API_KEY = "xxx"; } }
2.package_name.wxapi 新建 WXPayEntryActivity.java (路径和文件名必须是这个)
package com.iotlife.action.wxapi; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import com.iotlife.action.R; import com.iotlife.action.common.Constant; import com.iotlife.action.util.LogUtil; import com.iotlife.action.util.ThreadPoolUtil; import com.iotlife.action.util.ToastUtil; import com.iotlife.action.util.ViewUtil; import com.iotlife.action.util.WXUtil; import com.tencent.mm.opensdk.constants.ConstantsAPI; import com.tencent.mm.opensdk.modelbase.BaseReq; import com.tencent.mm.opensdk.modelbase.BaseResp; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; import com.tencent.mm.opensdk.openapi.WXAPIFactory; public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { public static void start(Context context) { context.startActivity(new Intent(context, WXPayEntryActivity.class)); } private IWXAPI api; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_wechat_pay); api = WXAPIFactory.createWXAPI(this, Constant.WX_CONSTANT.APP_ID); api.handleIntent(getIntent(), this); ViewUtil.$(this, R.id.btnPay).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ThreadPoolUtil.execute(new Runnable() { @Override public void run() { WXUtil.submitOrder(); } }); } }); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); } @Override public void onReq(BaseReq req) { } @Override public void onResp(BaseResp resp) { LogUtil.d("HttpUtil", "微信支付回调onPayFinish, errCode = " + resp.errCode); if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { if (resp.errCode == 0) { ToastUtil.show("支付成功"); } else { ToastUtil.show("支付失败"); } finish(); } } }
3.工具类 WXUtil.java
package com.iotlife.action.util; import android.util.Xml; import com.iotlife.action.application.EJYApplication; import com.iotlife.action.common.Constant; import com.tencent.mm.opensdk.modelpay.PayReq; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.WXAPIFactory; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.xmlpull.v1.XmlPullParser; import java.io.IOException; import java.io.StringReader; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class WXUtil { private static final String TAG = "HttpUtil"; private static final IWXAPI msgApi = WXAPIFactory.createWXAPI(EJYApplication.getInstance(), null); /** * 微信支付 * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1 * <p> * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3 * 注释分别为:字段名称,是否必填 */ public static void submitOrder() { PayReq req = new PayReq(); req.nonceStr = StringUtil.md5(UUID.randomUUID().toString()); LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(); map.put("appid", Constant.WX_CONSTANT.APP_ID); // 应用ID map.put("mch_id", Constant.WX_CONSTANT.MCH_ID);// 商户号 map.put("device_info", "WEB");// 设备号,否 map.put("nonce_str", req.nonceStr);// 随机字符串 // map.put("sign_type", "md5");// 签名类型,否 map.put("body", "body");// 商品描述 // map.put("detail", "detail");// 商品详情,否 map.put("attach", "attach");// 附加数据,否 map.put("out_trade_no", (System.currentTimeMillis() + 1415659990999L) + "");// 商户订单号 // map.put("fee_type", "CNY");// 货币类型,否 map.put("total_fee", "1");// 总金额,单位是分,不是元,不能有小数 map.put("spbill_create_ip", "14.23.150.211");// 终端IP map.put("time_start", "");// 交易起始时间,否 map.put("time_expire", "");// 交易结束时间,否 map.put("goods_tag", "");// 订单优惠标记,否 map.put("notify_url", "https://www.baidu.com");// 通知地址 map.put("trade_type", "APP");// 交易类型 // map.put("limit_pay", "no_credit");// 指定支付方式,否 String key = Constant.WX_CONSTANT.API_KEY; String sign = WXUtil.getSign(map, key); map.put("sign", sign); String entity = toXml(map); LogUtil.d(TAG, entity); byte[] buf = httpPost(entity); String content = new String(buf); LogUtil.d(TAG, "content " + content); Map<String, String> resultunifiedorder = decodeXml(content); req.appId = map.get("appid"); req.partnerId = map.get("mch_id"); if (resultunifiedorder != null) { req.prepayId = resultunifiedorder.get("prepay_id"); req.packageValue = "prepay_id=" + resultunifiedorder.get("prepay_id"); } req.timeStamp = String.valueOf(System.currentTimeMillis() / 1000); 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)); StringBuilder sb = new StringBuilder(); for (int i = 0; i < signParams.size(); i++) { sb.append(signParams.get(i).getName()); sb.append('='); sb.append(signParams.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(Constant.WX_CONSTANT.API_KEY); req.sign = StringUtil.md5(sb.toString()); LogUtil.d(TAG, "req.sign = " + req.sign); msgApi.registerApp(Constant.WX_CONSTANT.APP_ID); msgApi.sendReq(req); } private static byte[] httpPost(String entity) { final String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; 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) { LogUtil.d(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode()); return null; } return EntityUtils.toByteArray(resp.getEntity()); } catch (Exception e) { LogUtil.d(TAG, "httpPost exception, e = " + e.getMessage()); e.printStackTrace(); return null; } } 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(); } } /** * 微信公众平台支付接口调试工具 * https://pay.weixin.qq.com/wiki/tools/signverify/ * * @param map * @param key 商户Key * @return */ private static String getSign(Map<String, String> map, String key) { if (map == null || map.size() < 1) { LogUtil.d("HttpUtil", "map 为空"); return ""; } StringBuilder sb = new StringBuilder(); List list = new ArrayList<>(map.keySet()); Collections.sort(list); for (int i = 0; i < list.size(); i++) { if (map.get(list.get(i)) != null && !map.get(list.get(i)).equals("")) { if (list.get(i).equals("notify_url")) { sb.append(list.get(i)).append("=").append(map.get(list.get(i))).append("&"); } else { sb.append(list.get(i)).append("=").append(StringUtil.encoder(map.get(list.get(i)))).append("&"); } } } String stringA = sb.toString(); stringA = stringA.substring(0, stringA.length() - 1); String stringSignTemp = stringA + "&key=" + key; String sign = StringUtil.md5(stringSignTemp).toUpperCase(); LogUtil.d("HttpUtil", "stringA = " + stringA); LogUtil.d("HttpUtil", "stringSignTemp = " + stringSignTemp); LogUtil.d("HttpUtil", "sign = " + sign); return sign; } private static String toXml(Map<String, String> map) { if (map == null || map.size() < 1) { LogUtil.d("HttpUtil", "map 为空"); return ""; } StringBuilder sb = new StringBuilder("<xml>"); for (String key : map.keySet()) { if (map.get(key) != null && !map.get(key).equals("")) { sb.append("<").append(key).append(">").append(map.get(key)).append("</").append(key).append(">"); } } return sb.append("</xml>").toString(); } 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 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) { LogUtil.d(TAG, "xml decoder error" + e.toString()); } return null; } }