com.geekandroid.sdk.pay.impl.CHWeiXinPay.java Source code

Java tutorial

Introduction

Here is the source code for com.geekandroid.sdk.pay.impl.CHWeiXinPay.java

Source

/*******************************************************************************
 *
 * 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();
    }
}