1. 程式人生 > >Android微信支付功能整合【全攻略】

Android微信支付功能整合【全攻略】


遵循:BY-SA

作者:譚東

時間:2016年10月28日

環境:Windows 7

Android版微信支付官方文件和Demo問題很多,官方也沒有及時更新和細化開發整合文件。

這裡分享我整合Android客戶端微信支付的思路和部分程式碼。希望對大家有幫助。

遇到的問題無非以下幾種:

1、提示簽名不對;

2、打包簽名後的APK無法調起微信支付客戶端,直接返回回撥頁;

3、不支援中文的Body;

4、支付的錢倍數不對,因為微信的單位是分;

... ...

首先,本文針對的是最新版微信Android支付SDK3.1.1寫的,大家可以放心使用。

首先,把WXPayEntryActivity.java複製到我們的包名下的.wxapi目錄下,要一致。

 <activity
            android:name=".wxapi.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:screenOrientation="portrait" />
WXPayEntryActivity.java官方Demo裡有,我這裡也複製一份我的,僅供參考。
public class WXPayEntryActivity extends BaseActivity implements IWXAPIEventHandler {
    private IWXAPI api;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        api = WXAPIFactory.createWXAPI(this, Conf.APP_ID);
        api.handleIntent(getIntent(), this);
        getSupportActionBar().setIcon(R.drawable.logo_gray);
        getSupportActionBar().setTitle("購買積分");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        Drawable dw = getResources().getDrawable(R.drawable.color_bg);
        getSupportActionBar().setBackgroundDrawable(dw);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            this.finish();
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }

    @Override
    public void onReq(BaseReq baseReq) {
    }

    @Override
    public void onResp(BaseResp baseResp) {
        if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
            Log.d("info", "onPayFinish,errCode=" + baseResp.errCode);
            if (baseResp.errCode == 0) {
                ToastUtil.showToast(this, "支付成功");
                Intent intent = new Intent("ACTION_PAY");
                sendBroadcast(intent);
                this.finish();
            } else if (baseResp.errCode == -1) {
                ToastUtil.showToast(this, "配置錯誤");
                this.finish();
            } else if (baseResp.errCode == -2) {
                ToastUtil.showToast(this, "使用者取消");
                this.finish();
            }
        } else {
            ToastUtil.showToast(this, baseResp.errStr);
        }
    }
}

這裡說一下Android微信支付流程,這裡本地客戶端都處理了所有的流程。

客戶端把所有需要的資訊拼接為XML後,統一下單,傳送給微信伺服器API請求,獲取訂單id,也就是prepayId。獲取到這個prepayId後,我們再把必要的資料欄位sign簽名MD5後,調起微信支付客戶端就可以了。比支付寶麻煩很多。

1、在程式的啟動頁,例如歡迎頁就可以註冊微信API的ID了。

IWXAPI msgApi = WXAPIFactory.createWXAPI(this, Conf.APP_ID);
        msgApi.registerApp(Conf.APP_ID);
完畢。

2、接下來處理微信POST請求的必要引數的拼接和加密等處理。寫PayActivity.java

把必填的引數處理下:

nonce_str:隨機字串,不長於32位。

out_trade_no:商戶系統內部的訂單號,32個字元內、可包含字母。

spbill_create_ip:使用者端實際ip,16位,可寫固定值。

notify_url:暫時寫成固定的,http://www.weixin.qq.com/wxpay/pay.php。

最麻煩的,sign:32位簽名,參照簽名生成演算法

以上這些演算法我都會寫成工具類,供大家參考。

簽名演算法:


附上整個支付程式碼:

PayActivity.java裡關於支付的程式碼:

private IWXAPI api;
    private String stringA;
    private String noneString;
    private String out_trade_no;
    private String sign;
    private String prepayId;
    private String ip;
    private String body = "商品-積分充值";
    private static final String order_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//POST請求統一下單介面地址
    private String notify_url = "http://www.weixin.qq.com/wxpay/pay.php";
    private String entity;//XML形式的post請求實體

    private void payWeixin(int money) {
        api = WXAPIFactory.createWXAPI(this, Conf.APP_ID);
        try {
            body = new String(body.getBytes(), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        noneString = Utils.createRandomString(true, 32);//32位隨機字串
        out_trade_no = Utils.createRandomString(true, 20) + Utils.timeStamp();//30位內部隨機訂單號
        ip = "123.123.123.123";
        stringA = "appid=" + Conf.APP_ID + "&body=" + body + "&mch_id=" + Conf.MCH_ID + "&nonce_str=" + noneString + "¬ify_url=" + notify_url + "&out_trade_no=" + out_trade_no + "&spbill_create_ip=" + ip + "&" +
                "total_fee=" + money + "&trade_type=APP";
        String stringSignTemp = stringA + "&key=" + Conf.KEY;
        sign = Utils.getMD5(stringSignTemp).toUpperCase(Locale.getDefault());

        entity = "<xml><appid>" + Conf.APP_ID + "</appid><mch_id>" + Conf.MCH_ID + "</mch_id><nonce_str>" + noneString + "</nonce_str><sign>" + sign +
                "</sign><body>" + body + "</body><out_trade_no>" + out_trade_no + "</out_trade_no><total_fee>" + money +
                "</total_fee><spbill_create_ip>" + ip + "</spbill_create_ip><notify_url>" + notify_url + "</notify_url><trade_type>APP</trade_type></xml>";

        try {
            entity = new String(entity.getBytes(), "ISO8859-1");//想要支援中文的Boby,那就要把XML轉碼為ISO8859-1即可
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    byte[] buf = Utils.httpPost(order_url, entity);
                    Message message = new Message();
                    message.what = 0;
                    message.obj = buf;
                    handler.sendMessage(message);
                } catch (Exception e) {
                    Log.e("info", "異常:" + e.getMessage());
                }
            }
        }).start();
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    byte[] buf = (byte[]) msg.obj;
                    if (buf != null && buf.length > 0) {
                        String content = new String(buf);
                        OrderResult orderResult = Tools.parseXml(new ByteArrayInputStream(content.getBytes()));
                        if (!TextUtils.equals(orderResult.getReturnCode(), "SUCCESS")) {
                            Toast.makeText(PayActivity.this, orderResult.getReturnMsg(), Toast.LENGTH_SHORT).show();
                            return;
                        }
                        if (!TextUtils.equals(orderResult.getResultCode(), "SUCCESS")) {
                            Toast.makeText(PayActivity.this, orderResult.getErrorDesc(), Toast.LENGTH_SHORT).show();
                            return;
                        }
                        PayReq req = new PayReq();
                        req.appId = Conf.APP_ID;
                        req.partnerId = Conf.MCH_ID;
                        req.prepayId = orderResult.getPrepayId();
                        req.packageValue = "Sign=WXPay";
                        req.nonceStr = noneString;
                        String timeStamp = Utils.timeStamp();
                        req.timeStamp = timeStamp;
                        req.sign = Utils.getMD5("appid=" + Conf.APP_ID + "&noncestr=" + noneString + "&package=Sign=WXPay" +
                                "&partnerid=" + Conf.MCH_ID + "&prepayid=" + orderResult.getPrepayId() + "×tamp=" + timeStamp + "&key=" + Conf.KEY).toUpperCase(Locale.getDefault());
                        api.sendReq(req);
                    } else {
                        Log.d("PAY_GET", "伺服器請求錯誤");
                        Toast.makeText(PayActivity.this, "伺服器請求錯誤", Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    };

Utils工具類程式碼:
public class Utils {

    /**
     * 產生隨機字串
     *
     * @param numberFlag 是否允許有字母
     * @param length     隨機字串長度
     * @return 隨機字串
     */
    public static String createRandomString(boolean numberFlag, int length) {
        String retStr = "";
        String strTable = numberFlag ? "1234567890" : "1234567890abcdefghijkmnpqrstuvwxyz";
        int len = strTable.length();
        boolean bDone = true;
        do {
            retStr = "";
            int count = 0;
            for (int i = 0; i < length; i++) {
                double dblR = Math.random() * len;
                int intR = (int) Math.floor(dblR);
                char c = strTable.charAt(intR);
                if (('0' <= c) && (c <= '9')) {
                    count++;
                }
                retStr += strTable.charAt(intR);
            }
            if (count >= 2) {
                bDone = false;
            }
        } while (bDone);

        return retStr;
    }

    /**
     * 獲取MD5加密後的字串
     *
     * @param val 待加密字串
     * @return 加密後字串
     */
    public static String getMD5(String val) {
        byte[] m = new byte[0];
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(val.getBytes());
            m = md5.digest();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return getString(m);
    }

    private static String getString(byte[] b) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            sb.append(b[i]);
        }
        return sb.toString();
    }

    /**
     * 獲取10位長度的時間戳
     *
     * @return 10位時間戳
     */
    public static String timeStamp() {
        String time = String.valueOf(System.currentTimeMillis());
        return time.substring(0, 10);
    }


    public static byte[] httpGet(final String url) {
        if (url == null || url.length() == 0) {
            return null;
        }
        HttpClient httpClient = getNewHttpClient();
        HttpGet httpGet = new HttpGet(url);
        try {
            HttpResponse resp = httpClient.execute(httpGet);
            if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                return null;
            }
            return EntityUtils.toByteArray(resp.getEntity());

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

    public static byte[] httpPost(String url, String entity) {
        if (url == null || url.length() == 0) {
            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) {
                return null;
            }
            return EntityUtils.toByteArray(resp.getEntity());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    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 static OrderResult parseXml(InputStream is) {
        XmlPullParser parser = Xml.newPullParser();
        OrderResult orderResult = null;
        try {
            parser.setInput(is, "UTF-8");
            int type = parser.getEventType();
            while (type != XmlPullParser.END_DOCUMENT) {
                switch (type) {
                    case XmlPullParser.START_DOCUMENT:
                        break;
                    case XmlPullParser.START_TAG:
                        if (parser.getName().equals("xml")) {
                            orderResult = new OrderResult();
                        } else if (parser.getName().equals("return_code")) {
                            orderResult.setReturnCode(parser.nextText());
                        } else if (parser.getName().equals("return_msg")) {
                            orderResult.setReturnMsg(parser.nextText());
                        } else if (parser.getName().equals("result_code")) {
                            orderResult.setResultCode(parser.nextText());
                        } else if (parser.getName().equals("err_code_des")) {
                            orderResult.setErrorDesc(parser.nextText());
                        } else if (parser.getName().equals("prepay_id")) {
                            orderResult.setPrepayId(parser.nextText());
                        } else if (parser.getName().equals("sign")) {
                            orderResult.setSign(parser.nextText());
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        break;
                }

                type = parser.next();
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return orderResult;
    }
}

這樣整個微信Android支付整合就完畢了。

相關推薦

Android支付功能整合

遵循:BY-SA 作者:譚東 時間:2016年10月28日 環境:Windows 7 Android版微信支付官方文件和Demo問題很多,官方也沒有及時更新和細化開發整合文件。 這裡分享我整合Android客戶端微信支付的思路和部分程式碼。希望對大家有幫

Android分享功能整合開發指南(這一篇就夠了)

前言 本文介紹的只是微信開發中的一個功能,分享。看到網上很多關於微信分享的部落格、帖子,說實話,沒幾篇寫的全的,很多都是複製貼上,介紹的也不全,缺少程式碼的分析,關鍵性的程式碼總是漏一句兩句,看著就很難受。所以,在這裡我打算寫一篇關於微信分享的部落格,總結一下

幹貨:營銷引流方法

同時 線下 網站發布 有一個 nag 消費 ffffff 分享圖片 傳統 很多人問我有沒有快速加粉絲的方法,經過幾天的總結整理,整理出如下多種微信營銷免費快速加粉秘籍,希望對大家有幫助,請切記,無論那一種方法只要你執行力好都會起到很好的效果。方法不在於多,而在於極致,一定要

縱橫開闔-小程式之通訊錄

Create by jsliang on 2018-11-21 20:46:36 Recently revised in 2018-11-25 00:24:14  Hello 小夥伴們,如果覺得本文還不錯,記得給個 star , 你們的 star 是我學習的動力!GitHub 地址  開

小程序實現支付功能(可用)

arr 必須 enc red use sam func 結束 單表 原博: https://blog.csdn.net/fredrik/article/details/79697963 微信小程序實現微信支付功能 直接把裏面的參數替換成你的就

Android支付支付 簡單整合

最近專案需求 改版了支付方式,支付寶  微信都切換了 海外版,還集成了paypal,前幾天隨手記錄了一下paypal的整合,今天 整理一下 支付寶 和微信的,支付寶 微信 賬戶申請 應用建立就不說了,截圖太麻煩,這裡只貼 一些 關鍵程式碼片段,假設 支付寶 微信  賬號申請

整合ping++支付支付功能遇到的坑

1、匯入官方專案時,不能像常規那樣匯入專案時,刪掉一些資料夾,更改檔案中版本,什麼都不改,直接開啟即 可。錯誤時,android studio會報錯:android studio error: style attribute ‘@android:attr/windowEnterAni

關於android支付支付支付整合

最近專案中要整合微信和支付寶支付 在沒有接觸支付之間 覺得還是比較難的 但真正去實現的時候還是比較簡單的 就是有不少坑要去踩過之後才知道 支付寶支付 : 對於支付寶支付 我個人理解還是比較簡單的 https://open.alipay.com/platform/home.h

Android支付整合和踩過的坑

近公司需要微信支付,所以不得不去看看微信支付文件。但是你懂得,那文件寫的真帶勁,看不懂。我直接放棄,開始整合。但是調起微信支付的時候:結果碼為-1,心裡一驚,肯定哪裡錯了,就開始找坑。所以把自己解決的過程分享給大家,讓整合微信支付成為很容易的一件事。 2、我們需要的資源

Android 支付整合重點(已經看過官方開發文件)

整合微信支付重點,適用於有整合經驗並且已經看過開發文件的同學 1.申請開通 按照官方文件步驟 (註冊平臺賬號——認證(300 如果失敗3次需再付300認證,資訊提前確認)——建立應用稽核(簽名用微信的提取工具)——開通支付功能——整合) 2.整合

android H5呼叫支付功能之坑慘了

一路過關一路坑,1:微信開發平臺在建立應用時跟debug和release 包沒什麼關係,主要看的是包名、簽名、APP ID、商戶ID、金鑰、訂單號、隨機時間msgApi = WXAPIFactory.createWXAPI(this, "APP ID"); msgApi.re

Android支付整合流程及其常見錯誤

[支付寶整合傳送門:http://blog.csdn.net/hx7013/article/details/61476320] 一、你需要關心的東西 1.申請與認證 2.上傳金鑰(商戶KEY),包名和簽名的修改 3.服務端整合 4

H5調起支付功能

需要 con 返回 alert list 訂單 團隊 eve window 第一步:需要後端返回需要的以下參數: 該操作是你提交完訂單信息後在接口所返回的json, 其次將其存儲起來,我用的localStorage var payParams = {

支付功能

and ini edm this substring pac pfx inpu code js wx.request({ url: url + ‘/team!jfchongzhi.action?openid=‘ + openid + ‘&weibi

spring boot項目之支付功能實現詳細介紹

tab 流程 invalid body 正方形 無法 數據 fmt -s 對接微信支付功能主要有以下幾個步驟, 而其第一個關鍵點就是獲取OpenID,在這裏介紹兩種獲取方式: 一、微信授權 微信網頁授權 如果用戶在微信客戶端中訪問第三方網頁,公

小程序 使用支付功能實現在線支付訂單

navi order lose ray 如果 image 全部 extern base 以前做過PC頁面微信支付,但是這次在小程序 直接調用微信支付功能還是方便很多 先放個微信官方API鏈接:https://pay.weixin.qq.com/wiki/doc/api/wx

PHP實現 APP端支付功能

1.我封裝好的一個支付類檔案,多餘的東西都去除掉了,並且把配置引數放到了這個支付類中,只需要修改Weixinpayandroid方法內的幾個引數就可以直接複製使用: class Wxpayandroid { //引數配置 public $config = array( 'appid' =&

Android 支付的統一下單

準備工作 申請微信開發者賬號,新增應用及申請開通微信支付功能,如 檢視開通流程 統一下單的介面文件: 檢視介面 開發 ①下載sdk: sdk和demo下載 ②可以匯入包 在build.gradle檔案中,新增如下依賴即可: depende

支付功能實現

< view class= "container"> < input type= "text" bindinput= "getOrderCode" style= "border:1px solid #ccc;"

android 支付,body為中文字元,簽名錯誤

微信支付訂單生產方法: /** * 根據您的訂單資訊 生成 微信產品支付訂單資訊 */ private String createWeChatOrder() { StringBuffer xml = new StringBuffer();