安卓微信支付步骤简述

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

一: 定义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 有问题再补充

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值