Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> androidAPP 集成微信支付

androidAPP 集成微信支付

編輯:關於Android編程

最近項目裡面需要支付功能,boos一致決定用微信支付,所以在網上查了很多資料,說的不全,完了就找以前的同事指教。算是成功集成上去了。在這裡做個總結記錄。

1、在APP上集成微信支付,首先當然是當官網上去注冊並獲取到支付功能。這些不涉及到開發,官網上說的很詳細,這裡就不多做文章。獲取到這些能力了就為開發提供了條件了。開發中會用到的就是平台給的APPID、APPsercet、以及商戶平台上設置的APP_key。

2、具備了支付能力等前提條件之後,就是開發過程了。代碼裡面怎麼才能吊起支付了,參照官網上的DEMO自己也做了一些總結和各方大神的指教。分為了下面幾個步奏。

(1)、首先當然是將sdk配置進工程環境中,官網中下載Android端SDK,解壓後將libmmsdk.jar導入工程,然後將DEMO中Constant.java(這裡是參照官方demo的樣式寫的,當然也可以采用其他方式)、MD5.java、Util.java放入工程(我這裡用到了這些),這些先決條件有了之後就可以下一步寫代碼操作了。

(2)、生成訂單信息

生成訂單信息采用了如下方法生成,生成訂單信息需要簽名文件,所以裡面包含了生成簽名。微信要求所有請求采用XML參數形式,所有生產訂單信息之後又需要轉換成xml。訂單信息需要的請求參數可以到官網上去對照,這裡只加入了一些必要的參數。

生成訂單信息方法:

 

//獲取產品訂單信息
    private String genProductArgs() {
        StringBuffer xml = new StringBuffer();
        try {
            String nonceStr = genNonceStr();

            xml.append("");
            List packageParams = new LinkedList();

            packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID)); //APPID

            packageParams.add(new BasicNameValuePair("body", "單價:" + singlePrice + " x " + payment_num.getText().toString() + "份"));  //簡單描述

            packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));  //商戶ID

            packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));   //隨機字符串

            packageParams.add(new BasicNameValuePair("notify_url","http://www.weixin.qq.com/wxpay/pay.php")); //通知地址

            packageParams.add(new BasicNameValuePair("out_trade_no",getTrade()));  //商戶訂單號

            packageParams.add(new BasicNameValuePair("spbill_create_ip",getLocalHostIp())); //終端IP

            //double price = Double.parseDouble(payment_num.getText().toString()) * (Integer.parseInt(singlePrice) * 100);
            double price = Double.parseDouble(singlePrice) * 100 * n;
            int priceInt = (int) price;
            packageParams.add(new BasicNameValuePair("total_fee", priceInt+""));    //微信接收int型價格

            packageParams.add(new BasicNameValuePair("trade_type", "APP"));  //支付類型

            String sign = genAppSign(packageParams);
            packageParams.add(new BasicNameValuePair("sign", sign));  //簽名

            String xmlstring = parseNodeToXML(packageParams);   //轉化成xml

            return xmlstring;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

構造這個xml請求參數采用的是httpclient生成的,所以引入了某些包。也可以采用其他方式生成支付訂單,只要最後的形式與官網中的形式相同即可。

 

裡面涉及到某些參數的生成,這裡列出的是我們項目裡面的業務邏輯,當然不同項目可定是不同的。

 

//獲取訂單號
    private String getTrade(){
        long nowTime = System.currentTimeMillis();
        SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmmss");
        return format.format(new Date(nowTime));
    }



    //獲取支付簽名Sign
    StringBuilder sb = new StringBuilder();
    private String genAppSign(List 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(Constants.API_KEY);
        this.sb.append("sign str\n" + sb.toString() + "\n\n");
        String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
        return appSign;
    }

    //獲取隨機字符串
    private String genNonceStr() {
        Random random = new Random();
        return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
    }

    /**
     * 解析為xml格式
     * @param treeNodes
     * @return
     */
    public String parseNodeToXML(List treeNodes) {
        StringBuffer xmlnodes = new StringBuffer();
        if (treeNodes != null && treeNodes.size() > 0) {
            xmlnodes.append("");
            for (int i = 0; i < treeNodes.size(); i++) {
                NameValuePair node = treeNodes.get(i);
                xmlnodes.append("<"+node.getName()+">").append(node.getValue()).append("");
            }
            xmlnodes.append("");
        }
        //return xmlnodes.toString();
        String xml = xmlnodes.toString();
        try {
            xml = new String(xml.toString().getBytes(), "ISO8859-1");  //商品詳情為中文,將其轉化為統一編碼,不然獲取perpred_id失敗
            return xml;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }


    //獲取手機IP
    public String getLocalHostIp() {
        String ipaddress = "";
        try {
            Enumeration en = NetworkInterface.getNetworkInterfaces();
            // 遍歷所用的網絡接口
            while (en.hasMoreElements()) {
                NetworkInterface nif = en.nextElement();// 得到每一個網絡接口綁定的所有ip
                Enumeration inet = nif.getInetAddresses();
                // 遍歷每一個接口綁定的所有ip
                while (inet.hasMoreElements()) {
                    InetAddress ip = inet.nextElement();
                    if (!ip.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ip.getHostAddress())) {
                        return ip.getHostAddress();
                    }
                }
            }
        }
        catch (SocketException e) {
            Log.e("feige", "獲取本地ip地址失敗");
            e.printStackTrace();
        }
        return ipaddress;
    }

 

(3)、訪問微信後台指定接口,獲取perpay_id。

可以說前面的都是為了獲取這個perpay_id做准備的,官網上給出的指定接口是“https://api.mch.weixin.qq.com/pay/unifiedorder” 請求采用官網demo中util提供的請求方式

這裡采用異步處理方式,當請求指定接口得到perapy_id之後直接吊起支付的方式。

 

 

//調用支付獲取id
    public void gotoWechat() {
        new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] objects) {   //獲取Prepay_id
                String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
                String entity = genProductArgs();   //獲取訂單信息
                byte[] buf = Util.httpPost(url, entity);
                String content = new String(buf);  //請求成功返回的信息
                //Log.e("orion", content);
                try {
                    xmlParseTest(content);  //解析返回的信息
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Object o) {
                super.onPostExecute(o);
                wechatPay();
            }
        }.execute();
    }


 

請求成功返回的數據當然也是xml格式的,需要解析並從中取到perpay_id(返回的結果不止perpay_id,包括其他信息,個人感覺吊起支付只需要perpay_id就行了)。這裡也是參考demo中的方式將獲取到的信息通過xml解析到

WeixinParentId對象當中。

/** * 解析xml * 返回prepay_id * 通過對象Books獲取數據 */ WeixinParentId book = null; //通過對象Books獲取數據 public void xmlParseTest(String str) throws IOException, XmlPullParserException { XmlPullParser pullParser = Xml.newPullParser(); //獲取XmlPullParser對象 //InputStream is = getContext().getAssets().open("parse.xml"); //解析文本 ByteArrayInputStream is = new ByteArrayInputStream(str.getBytes("UTF-8")); ArrayList books = null ; pullParser.setInput(is, "UTF-8"); int type = pullParser.getEventType(); //獲取事件類型 while (type != pullParser.END_DOCUMENT) { //結束文本 switch(type){ case XmlPullParser.START_DOCUMENT: //開始文本 books = new ArrayList(); break; case XmlPullParser.START_TAG: //開始標記  if (pullParser.getName().equals("xml")) { book = new WeixinParentId(); }else if (pullParser.getName().equals("return_msg")) { type = pullParser.next(); //指向下一個位置,不然無法獲取數據 book.setReturn_msg(pullParser.getText()); }else if (pullParser.getName().equals("appid")) { type = pullParser.next(); book.setAppid(pullParser.getText()); }else if (pullParser.getName().equals("prepay_id")) { type = pullParser.next(); book.setPrepay_id(pullParser.getText()); } break; case XmlPullParser.END_TAG: //結束標記  if (pullParser.getName().equals("book")) { books.add(book); book = null; //置為空釋放資源 } break; } type = pullParser.next(); //指向下一個標記 } //Log.e("test", "book------id----" + book.getPrepay_id()); }

成功執行這不之後,book對象中perpay_id已經被賦值。只需在異步中取出使用即可。
//獲取到perpay_id之後吊起微信支付 protected void wechatPay() { PayReq req = new PayReq(); req.appId = Constants.APP_ID; req.partnerId = Constants.MCH_ID; req.prepayId = book.getPrepay_id(); req.packageValue = "Sign=WXPay"; req.nonceStr = genNonceStr(); req.timeStamp = String.valueOf(genTimeStamp()); List signParams = new LinkedList(); 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"); // 在支付之前,如果應用沒有注冊到微信,應該先調用IWXMsg.registerApp將應用注冊到微信 //Log.e("test","book.getPrepay_id()----------"+book.getPrepay_id()+"-------genNonceStr()-------"+genNonceStr()+"--------genTimeStamp()-------"+genTimeStamp()+"---genAppSign(signParams)--"+genAppSign(signParams)); api.sendReq(req); // dialog.dismiss(); } //獲取時間搓 private long genTimeStamp() { return System.currentTimeMillis() / 1000; }

把前面的異步操作方法賦給一個按鈕點擊事件,如果所有步奏正確,就可以進入支付界面了,如下圖:

\

點擊確支付當然就是輸入密碼什麼的操作了,支付成功後有一個反饋信息如下圖:

\

點擊完成,當然是回到APP咯,這裡就是微信提供的一個回調了。也就是官網上強調的wxapi包下的

WXPayEntryActivity裡的Onresp()方法中做回調處理,該包必須在項目工程包目錄下才能回調成功。下面貼出的是示例工程結構

\

在回調中彈出了對話框提示用戶支付成功並處理其他邏輯。

 

 

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

    private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";

    private IWXAPI api;


    @Override public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

//        setContentView(R.layout.activity_main2);
        api = WXAPIFactory.createWXAPI(this, Constants.APP_ID);
        api.handleIntent(getIntent(), this);
        api.registerApp(Constants.APP_ID);
    }


    @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) {
        int errCode = resp.errCode;

        if (errCode == 0) {

            // 0成功 展示成功頁面
            // Intent intent = new Intent("name");
            // sendBroadcast(intent);
            // Log.e("test","支付成功的回調方法--onResp--");
            // Toast.makeText(this,"支付完成",Toast.LENGTH_SHORT).show();

            new AlertDialog.Builder(this).setMessage("支付成功").setPositiveButton("確定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    finish();
                    PaymentActivity.instance.finish();

                    Intent intent = new Intent(WXPayEntryActivity.this, PuzzGameActivity.class);
                    intent.putExtra("ISPLAY",true);
                    startActivity(intent);

                }
            }).setTitle("提示").create().show();

            Toast.makeText(this,"點擊確定按鈕開始參與拼圖游戲活動",Toast.LENGTH_LONG).show();

        }
        else if (errCode == -1) {
            //-1 錯誤 可能的原因:簽名錯誤、未注冊APPID、項目設置APPID不正確、注冊的APPID與設置的不匹配、其他異常等。
            new AlertDialog.Builder(this).setMessage("支付出錯").setPositiveButton("確定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    finish();
                }
            }).setTitle("提示").create().show();
            finish();
        }
        else if (errCode == -2) {
            //-2 用戶取消 無需處理。發生場景:用戶不支付了,點擊取消,返回APP。
            finish();
        }
    }


}

這樣所有步奏就幾乎完全了,結合官方示例和文檔,應該可以快速的在項目中加入支付功能了。

 

當然,這裡所涉及到的步奏全是在app服務端進行的,官網上介意將獲取簽名等操作放在服務後台進行,也就是客服端將訂單信息傳給服務端。服務端返回吊起支付必要的信息

(包括perpay_id、商戶id 、簽名等),然後又客戶端吊起微信支付的。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved