Java tutorial
/******************************************************************************* * * Copyright (c) 2016 Mickael Gizthon . All rights reserved. Email:2013mzhou@gmail.com * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.geekandroid.sdk.pay.impl; import android.app.Activity; import android.os.Handler; import android.os.Message; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.util.Xml; import com.geekandroid.sdk.pay.IPay; import com.geekandroid.sdk.pay.utils.MD5; import com.geekandroid.sdk.pay.utils.Util; import com.geekandroid.sdk.pay.utils.WeakHandlerNew; import com.tencent.mm.sdk.modelpay.PayReq; import com.tencent.mm.sdk.openapi.IWXAPI; import com.tencent.mm.sdk.openapi.WXAPIFactory; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.xmlpull.v1.XmlPullParser; import java.io.StringReader; import java.math.BigDecimal; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; public abstract class CHWeiXinPay extends IPay { //appid //? androidmanifest.xml?.PayActivityd<data android:scheme="wxb4ba3c02aa476ea1"/>appid //appid private static String APP_ID = ""; //? private static String MCH_ID = ""; // API? private static String API_KEY = ""; private static String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder"); protected IWXAPI msgApi; private WeakHandlerNew handler = new WeakHandlerNew(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { handleRealMessage(msg); return false; } }); public void setKeyAndID(String apiKey, String appid, String mchid) { API_KEY = apiKey; APP_ID = appid; MCH_ID = mchid; } public void registerApp() { msgApi.registerApp(APP_ID); } @Override public void requestOrder(Map<String, Object> params, RequestCallBack<String> callBack) { } @Override public void init(Activity activity) { super.init(activity); msgApi = WXAPIFactory.createWXAPI(activity, null); if (msgApi.isWXAppInstalled()) { registerApp(); } else { Log.e("init", ""); } } public static double mul(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); } public void doRealPay(final Map<String, Object> parameters) { if (TextUtils.isEmpty(APP_ID) || TextUtils.isEmpty(MCH_ID) || TextUtils.isEmpty(API_KEY)) { Log.e("doRealPay", "APP_ID MCH_IDAPI_KEY"); return; } //check request if (isEmpty(parameters.get("body")) || isEmpty(parameters.get("out_trade_no")) || isEmpty(parameters.get("total_fee")) || isEmpty(parameters.get("spbill_create_ip")) || isEmpty(parameters.get("notify_url"))) { Log.e("doRealPay", "?[ detail, out_trade_no, spbill_create_ip, total_fee, notify_url]"); return; } if (parameters.get("out_trade_no").toString().length() > 32) { Log.e("doRealPay", "?? 32 ?"); return; } //??? ? ? double ???? if (parameters.get("total_fee") instanceof Double) { String totalfee = parameters.get("total_fee").toString(); int realMoney = (int) mul(Double.parseDouble(totalfee), 100); parameters.put("total_fee", realMoney); } Runnable payRunnable = new Runnable() { @Override public void run() { boolean isSuccess = pay(parameters); Message msg = new Message(); msg.what = WX_SDK_PAY_FLAG; msg.obj = isSuccess; handler.sendMessage(msg); } }; // Thread payThread = new Thread(payRunnable); payThread.start(); } /** * Handler ? */ public abstract void callClientSuccess(boolean isSuccess); @Override public void getPayResult(Map<String, Object> params, RequestCallBack<String> callBack) { } protected void handleRealMessage(Message msg) { if (msg.what == WX_SDK_PAY_FLAG) { boolean isSuccess = (boolean) msg.obj; hideProgress(); callClientSuccess(isSuccess); } } /** * @param parameters ?? | ???? | | | | ?? * ID | appid | | String(32) | wxd678efh567hg6787 | ?APPID | * ? | mch_id | | String(32) | 1230000109 | ?? | * ? | device_info | ? | String(32) | 013467007045764 | ?(?ID)"WEB" | * ? | nonce_str | | String(32) | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | ??32????? | * ?? | sign | | String(32) | C380BEC2BFD727A4B6845133519F3AD6 | ?????? | * ??? | body | | String(128) | Ipad | mini 16G | ????? | * ? | detail | ? | String(8192) | Ipad | mini 16G | ??? | * ? | attach | ? | String(127) | | ?API???? | * ?? | out_trade_no | | String(32) | 20150806125346 | ??,32????, | ??? | * ? | fee_type | ? | String(16) | CNY | ?ISO | 4217????CNY?? | * ? | total_fee | | Int | 888 | ?????? | * IP | spbill_create_ip | | String(16) | 123.12.12.123 | ip | * | time_start | ? | String(14) | 20091225091010 | ???yyyyMMddHHmmss200912259101020091225091010? | * ? | time_expire | ? | String(14) | 20091227091010 | * ??yyyyMMddHHmmss200912279101020091227091010? * ?5 | * ? | goods_tag | ? | String(32) | WXG | ????? | * ? | notify_url | | String(256) | http://www.weixin.qq.com/wxpay/pay.php | ?url?url??? | * | trade_type | | String(16) | APP | | * ? | limit_pay | ? | String(32) | no_credit | no_credit--?? | */ public boolean pay(Map<String, Object> parameters) { boolean result = false; try { List<NameValuePair> packageParams = getNameValuePairs(parameters); String sign = genPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); String xmlstring = toXml(packageParams); String entity = new String(xmlstring.getBytes(), "ISO8859-1"); byte[] buf = Util.httpPost(url, entity); String content = new String(buf); Map<String, String> xml = decodeXml(content); PayReq payReq = genPayReq(xml); result = sendPayReq(payReq); Log.i("result", String.valueOf(result)); } catch (Exception e) { e.printStackTrace(); } return result; } @NonNull private List<NameValuePair> getNameValuePairs(Map<String, Object> parameters) { //? final String body = parameters.get("body").toString(); final String out_trade_no = parameters.get("out_trade_no").toString(); final String spbill_create_ip = parameters.get("spbill_create_ip").toString(); final int total_fee = Integer.parseInt(parameters.get("total_fee").toString()); final String notify_url = parameters.get("notify_url").toString(); //?? final String detail = optValue(parameters, "detail"); final String attach = optValue(parameters, "attach"); final String device_info = optValue(parameters, "device_info"); final String fee_type = optValue(parameters, "fee_type"); final String time_start = optValue(parameters, "time_start"); final String time_expire = optValue(parameters, "time_expire"); final String goods_tag = optValue(parameters, "goods_tag"); final String limit_pay = optValue(parameters, "limit_pay"); String nonce_str = genNonceStr(); List<NameValuePair> packageParams = new LinkedList<>(); packageParams.add(new BasicNameValuePair("appid", APP_ID)); addPackageParams(packageParams, "attach", attach); packageParams.add(new BasicNameValuePair("body", body)); addPackageParams(packageParams, "detail", detail); addPackageParams(packageParams, "device_info", device_info); addPackageParams(packageParams, "fee_type", fee_type); addPackageParams(packageParams, "goods_tag", goods_tag); addPackageParams(packageParams, "limit_pay", limit_pay); packageParams.add(new BasicNameValuePair("mch_id", MCH_ID)); packageParams.add(new BasicNameValuePair("nonce_str", nonce_str)); packageParams.add(new BasicNameValuePair("notify_url", notify_url)); packageParams.add(new BasicNameValuePair("out_trade_no", out_trade_no)); packageParams.add(new BasicNameValuePair("spbill_create_ip", spbill_create_ip)); addPackageParams(packageParams, "time_expire", time_expire); addPackageParams(packageParams, "time_start", time_start); packageParams.add(new BasicNameValuePair("total_fee", String.valueOf(total_fee))); packageParams.add(new BasicNameValuePair("trade_type", "APP")); return packageParams; } public void addPackageParams(List<NameValuePair> packageParams, String key, String value) { if (!TextUtils.isEmpty(value)) { packageParams.add(new BasicNameValuePair(key, value)); } } public String optValue(Map<String, Object> map, String key) { if (map.containsKey(key)) { return map.get(key).toString(); } return null; } private PayReq genPayReq(Map<String, String> resultUnifiedOrder) { PayReq req = new PayReq(); req.appId = APP_ID; req.partnerId = MCH_ID; req.prepayId = resultUnifiedOrder.get("prepay_id"); 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; } private boolean sendPayReq(PayReq req) { msgApi.registerApp(APP_ID); return msgApi.sendReq(req); } private static String genNonceStr() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } private String genPackageSign(List<NameValuePair> params) { if (params == null || params.isEmpty()) { return ""; } 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(API_KEY); String md5 = MD5.getMessageDigest(sb.toString().getBytes()); if (TextUtils.isEmpty(md5)) { return ""; } return md5.toUpperCase(); } private static String toXml(List<NameValuePair> params) { StringBuilder sb = new StringBuilder(); sb.append("<xml>"); for (int i = 0; i < params.size(); i++) { sb.append("<"); sb.append(params.get(i).getName()); sb.append(">"); sb.append(params.get(i).getValue()); sb.append("</"); sb.append(params.get(i).getName()); sb.append(">"); } sb.append("</xml>"); return sb.toString(); } private static Map<String, String> decodeXml(String content) { try { Map<String, String> 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)) { // student xml.put(nodeName, parser.nextText()); } break; case XmlPullParser.END_TAG: break; } event = parser.next(); } return xml; } catch (Exception e) { e.printStackTrace(); } return null; } private static long genTimeStamp() { return System.currentTimeMillis() / 1000; } private 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(API_KEY); String md5 = MD5.getMessageDigest(sb.toString().getBytes()); if (TextUtils.isEmpty(md5)) { return ""; } return md5.toUpperCase(); } }