Notes on Wechat Payment

1. Development preparation
1.Registered Wechat Developer Account
2.Official Documents of Wechat
3.Official Demo
4. Registered Wechat Business Number

Above 1 and 2 see the official registration process to ok, in the open platform to register your current development of the App application, where you need the App application signature, Wechat official provides a tool to view signatures (download signature tool in resource download). It is important to note that after the approval of App, you need to apply for payment function. The relevant business number is what you need in development (business ID).

2. Resource allocation
1. Import the Jar Payment Payment Payment Payment Payment Payment by Wechat
2. The permissions required to add Wechat Payment to Manifest are as follows:


Note: In the process of integration, according to the directory structure of src in the official Demo, that is, the package name of the application +. wxapi
In the official Demo, the logic processing of tweeting payment has been handled in the background (there is no trivial matter about money), so the payment function is successful just by sending back the data requested by the interface (on the importance of good backstage personnel). However, I have not encountered such a good thing as the nonce_str, sig needed by Wechat. N, prepay_id needs to be handled by itself.

It is strongly recommended that you read the code logically API List

##### 3. Part of the logic code:
ruby
// When a wechat sends a request to a third party application, it calls back to this method.
@Override
public void onReq(BaseReq req) {
Log.e("11111111111", req.toString());
}

    //The response of a third-party application to a request sent to Wechat after processing is called back to this method.
    @Override
    public void onResp(BaseResp resp) {
        if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle(R.string.app_tip);
            String code = String.valueOf(resp.errCode);
            if (code.equals("0")) {
                builder.setMessage(getString(R.string.pay_result_callback_msg, "Successful payment"));
                builder.show();
            } else if (code.equals("-1")) {
                builder.setMessage(getString(R.string.pay_result_callback_msg, "Failure to pay"));
                builder.show();
            } else if (code.equals("-2")) {
                builder.setMessage(getString(R.string.pay_result_callback_msg, "Users Cancel Payment"));
                builder.show();
            }


        }
    }
 //Wechat Payment
    private class GetPrepayIdTask extends AsyncTask<Void, Void, Map<String, String>> {
        private StringBuffer sb = new StringBuffer();
        private Map<String, String> result;
        private PayReq req = new PayReq();
        private IWXAPI mApi;
        private Context mContext;
        private double price;
        private String orderNo;
        private String orderNos;
        private ProgressDialog dialog;
        public GetPrepayIdTask(Context context, double price, String orderNo, String orderNos) {
            mApi = WXAPIFactory.createWXAPI(context, null);
            this.mContext = context;
            this.price = price;
            this.orderNo = orderNo;
            this.orderNos = orderNos;
        }
        @Override
        protected void onPreExecute() {
            dialog = ProgressDialog.show(WXPayEntryActivity.this, "Tips", "Getting Advance Payment Orders...");
        }
        @Override
        protected void onPostExecute(Map<String, String> resultMap) {
            if (dialog != null) {
                dialog.dismiss();
            }
            sb.append("prepay_id\n" + resultMap.get("prepay_id") + "\n\n");
            result = resultMap;
            genPayReq();
            mApi.registerApp(wxId);
            //Payment transfer
            mApi.sendReq(req);
        }

      // Generating Final Signature,And the final request parameters
        private void genPayReq() {
            req.appId = wxId;
            req.partnerId = wxPartenr;
            req.prepayId = result.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);

            sb.append("sign\n" + req.sign + "\n\n");

            Log.e("orion", signParams.toString());
        }

        private String genAppSign(List<NameValuePair> signParams) {
            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(wxPartenrKey);

            this.sb.append("sign str\n" + sb.toString() + "\n\n");
            String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
            Log.e("orionAppSign", appSign);
            return appSign;
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
        }


        @Override
        protected Map<String, String> doInBackground(Void... params) {
            String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
            String entity = genProductArgs();
            //post request
            byte[] buf = Util.httpPost(url, entity);

            String content = new String(buf);
            Log.e("orion", content);
            Map<String, String> xml = decodeXml(content);

            return xml;
        }
    }



   // with xml The way to unify the single parameter, obtain prepay_id
    private String genProductArgs() {
        StringBuffer xml = new StringBuffer();
        try {
            String nonceStr = genNonceStr();

            xml.append("</xml>");
            List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
            packageParams.add(new BasicNameValuePair("appid", wxId));
            packageParams.add(new BasicNameValuePair("body", mPaySn + ""));
            packageParams.add(new BasicNameValuePair("mch_id", wxPartenr));
            packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
            packageParams.add(new BasicNameValuePair("notify_url", notify_url));
            packageParams.add(new BasicNameValuePair("out_trade_no", mPaySn));
            double moneyOfCent = MathUtil.multiply(mPrice + "", "100");
            int total_fee = (int) moneyOfCent;

            packageParams.add(new BasicNameValuePair("spbill_create_ip", "127.0.0.1"));
            packageParams.add(new BasicNameValuePair("total_fee", total_fee + ""));
            packageParams.add(new BasicNameValuePair("trade_type", "APP"));
            //autograph
            String sign = genPackageSign(packageParams);
            packageParams.add(new BasicNameValuePair("sign", sign));

            String xmlstring = toXml(packageParams);

            return xmlstring;

        } catch (Exception e) {
            // Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage());
            return null;
        }

    }

    private 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) {
                            // Instantiate student objects
                            xml.put(nodeName, parser.nextText());
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        break;
                }
                event = parser.next();
            }

            return xml;
        } catch (Exception e) {
            Log.e("orion", e.toString());
        }
        return null;

    }

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

        Log.e("orion", sb.toString());
        return sb.toString();
    }

 // Generate signature
    private 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(wxId);

        String packageSign = MD5.getMessageDigest(sb.toString().getBytes())
                .toUpperCase();
        Log.e("orionStringBuilder", sb.toString());
        Log.e("orionAppMd5", packageSign);
        return packageSign;
    }


   //Random string
    private String genNonceStr() {
        Random random = new Random();
        return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
    }


   // time stamp
    private long genTimeStamp() {
        return System.currentTimeMillis() / 1000;
    }

##### 4. Summary:
GetPrepayIdTask inherits from AsyncTask, which assists in background execution and then updates the UI
1. Mr. A prepaid transaction order (requiring xml to unify interface parameters and generating signatures) is obtained, and then the parameters are re-signed and transmitted to APP to initiate payment.
2. When signing parameters, we must ensure orderliness (sorting ASCII codes by parameter names from small to large), and the signature should be converted to uppercase form.
3.App_Id does not match the business ID. Look at the number of businesses bound in the open platform.
4. The possible reasons for the Return-1 of transfer payment are signature error, unregistered APPID, incorrect project setting APPID, mismatch between registered APID and settings, and other exceptions.
5. Wechat pays for SDK relatively fast update, so we still need to see more official documents in the development process.

Keywords: xml Ruby ascii SDK

Added by nickholt1972 on Sun, 07 Jul 2019 04:58:48 +0300