1. 程式人生 > >微信、支付寶、銀聯開發遇到的那些坑

微信、支付寶、銀聯開發遇到的那些坑

出於安全考慮,驗籤我們都是放到後臺進行驗籤的。對於我們移動端節省了很多的勞動力。

支付介面如下:

這裡寫圖片描述

支付完成介面如下:

這裡寫圖片描述

ok,接下來開始我們輕鬆的開發之旅:

準備:需要以公司名義,在支付寶,微信等平臺上開通公司賬戶並且認證,如:支付過程中需要公司的帳號和商戶號。

支付寶:

1、獲取訂單資訊(根據自己公司的實際情況:可以在服務端完成,也可以在本地完成)

2、客戶端拿這些訂單資訊向伺服器後臺進行請求,返回支付簽名信息signInfo

3、app攜帶支付資訊,呼叫支付介面請求支付寶客戶端,從而調起支付介面

/**
 * 支付寶進行請求
 *
 * @param signInfo
 */
private void payToOrderService(final String signInfo) { new Thread() { @Override public void run() { super.run(); PayTask payTask = new PayTask(MyScannerPayActivity.this); String result = payTask.pay(signInfo, true); Map<String, String> result = payTask.payV2(signInfo, true
); Message message = mHandler.obtainMessage(); message.what = SDK_PAY_FLAG; message.obj = result; mHandler.sendMessage(message); } }.start(); }

4、使用者操作,輸入密碼支付,支付成功;直接返回取消支付;出現錯誤,支付失敗;進入支付介面,但輸入密碼支付,支付待確認;

5、支付寶客戶端將支付結果告訴app客戶端,商戶伺服器通知app伺服器支付結果;

6、app客戶端處理支付結果;

7、app伺服器處理支付結果。

app客戶端結果處理程式碼:

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case SDK_PAY_FLAG:
                    PayResult payResult = null;
                    try {
                        payResult = new PayResult((Map<String, String>) msg.obj);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    /**
                     對於支付結果,請商戶依賴服務端的非同步通知結果。同步通知結果,僅作為支付結束的通知。
                     */
                    String resultInfo = payResult.getResult();// 同步返回需要驗證的資訊
                    String resultStatus = payResult.getResultStatus();
                    // 判斷resultStatus 為9000則代表支付成功
                    if (TextUtils.equals(resultStatus, PAY_OK)) {

                        ActivityUtils.showActivity(MyScannerPayActivity.this, ScannerPaySuccessActivity.class);
                        finish();
                    } else if (TextUtils.equals(resultStatus, PAY_FAILED)) {//------------------------->支付失敗
                        // 該筆訂單真實的支付結果,需要依賴服務端的非同步通知。
                        Toast.makeText(MyScannerPayActivity.this, "" + payResult.getMemo(), Toast.LENGTH_LONG).show();
                    } else if (TextUtils.equals(resultStatus, PAY_CANCLE)) {//-------------------------->交易取消
                        Toast.makeText(MyScannerPayActivity.this, "" + payResult.getMemo(), Toast.LENGTH_LONG).show();
                    } else if (TextUtils.equals(resultStatus, PAY_NET_ERR)) {//------------------------->網路出現錯誤
                        Toast.makeText(MyScannerPayActivity.this, "" + payResult.getMemo(), Toast.LENGTH_LONG).show();
                    } else if (TextUtils.equals(resultStatus, PAY_WAIT_CONFIRM)) {//--------------------->交替等待
                    }
                    break;
            }
        }
    };

微信支付:

先上官方流程圖

這裡寫圖片描述

1、接入流程

申請開發者賬號

2、程式碼整合

1.客戶端程式碼得到使用者購買的商品資訊,將之傳給自己公司app伺服器,引數包含但不限於以下:

HashMap<String ,String> params = getHeadMap();
params.put("appid", appID);// 微信appid,選擇性上傳,伺服器寫死亦可
params.put("money", money);// 支付金額,單位:分
params.put("goodName", goodsName);// 商品名稱
params.put("productNum", String.valueOf(12));// 商品的數量

2.app伺服器呼叫微信 統一下單 介面,得到prepayId並返回客戶端

3.app客戶端使用prepayId和商品資訊呼叫sdk進行微信支付請求

IWXAPI mWxApi = WXAPIFactory.createWXAPI(mContext, WX_APPID, true);
mWxApi.registerApp(WX_APPID);
/**
 * 請求app伺服器得到的回撥結果
 */
@Override
public void onGet(JSONObject jsonObject) {
    if (mWxApi != null) {
        PayReq req = new PayReq();
        req.appId = WX_APPID;// 微信開放平臺稽核通過的應用APPID

        try {
            req.partnerId = jsonObject.getString("partnerid");// 微信支付分配的商戶號
            req.prepayId = jsonObject.getString("prepayid");// 預支付訂單號,app伺服器呼叫“統一下單”介面獲取
            req.nonceStr = jsonObject.getString("noncestr");// 隨機字串,不長於32位,伺服器小哥會給咱生成
            req.timeStamp = jsonObject.getString("timestamp");// 時間戳,app伺服器小哥給出
            req.packageValue = jsonObject.getString("package");// 固定值Sign=WXPay,可以直接寫死,伺服器返回的也是這個固定值
            req.sign = jsonObject.getString("sign");// 簽名,伺服器小哥給出,他會根據:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3指導得到這個
        } catch (JSONException e) {
            e.printStackTrace();
        }
        mWxApi.sendReq(req);
        Log.d("發起微信支付申請");
    }
}

4.微信回撥客戶端支付結果

5.微信伺服器非同步通知app伺服器支付結果

注意:

1.首先如果要使用微信支付的話

待稽核通過後,會得到一個AppID和AppSecret,AppID分享和支付都要用到,AppSecret沒什麼實際用途,此時微信分享能力是直接擁有的,支付能力還要額外申請,其中涉及到財務資訊等

最好讓公司財務部門去申請,申請成功後會拿到一個商戶id,後面生成sign時會用到。
只有所有稽核都通過後,才可呼叫微信支付功能,這點是前提。

2.微信分享和微信支付SDK是同一個架包,名為libammsdk.jar。

3.官方開發文件中有一處錯誤,需要注意下,如下圖最後一行引數req應該為request,照搬程式碼的估計IDE也不會放過你,哈哈

4.測試微信支付時,務必對自己的App做正式簽名,因為一開始就在微信平臺註冊過簽名信息,微信SDK會做校驗,只有這樣才能調起微信分享和微信支付,直接debug版的包則絕對調不起來,這點務必注意,很多人是跌在這裡了!當初做微信分享曾遇到過,所以會很留心,也因為如此,如果微信分享能調起來,微信支付不行,那就不要懷疑簽名問題了。但支付寶除錯是無需正式簽名!

5.還是簽名,網上有人說要注意大小寫,這點其實是不必的。在微信開放平臺看到稽核通過的App的簽名是大寫的,而用微信簽名獲取工具獲得的則顯示小寫,這個沒關係,不要貿然改動平臺註冊資訊,不然又可能導致漫長的稽核等待,上面也說了,微信分享如可以,那就不是簽名問題。

6.來說下官方demo,這東西害人不淺啊!很多人蔘考其寫法,如生成sign放在客戶端啊,調支付的Activity新增intent-filter啊,最主要的還是簽名問題。其實客戶端邏輯很簡單,直接上手整合即可,demo看看邏輯就行,照抄小心掉坑裡。

7.網上有人說需要給呼叫支付的Activity配置如下intent-filter(見下圖),可能也是被demo誤導了

8.對於errCode返回-1,有人說清除微信快取或切換賬戶就好了,這種解決方案治標不治本啊,根本不能算解決方案。雖然我沒遇到能用這方法解決的問題,但目測是簽名的問題,建議還得找到真正的問題所在。

9.生成sign時特別需要注意:

首先將key-value鍵值對拼成字串,注意key都要小寫,如appid,noncestr,package,partnerid,prepayid,timestamp,key,並且名字得按上述名稱
我們遇到的錯誤就是因為partnerid寫成了partnerId,prepayid寫成了PrepayId,當然我們是在服務端寫的,如果在客戶端生成sign的話,也需要注意大小寫及名稱,詳細資訊請參考官方文件。
還有這裡的key並非AppID或AppSectet,而是在商戶平臺設定的,官方描述為“key設定路徑:微信商戶平臺(pay.weixin.qq.com)–>賬戶設定–>API安全–>金鑰設定”。對於noncestr,申請prepayid和生成sign時兩次需要用到,由於iOS同事看到相關文章說noncestr前後需要一致,因此這個隨機字串我們是設定成一樣的了,這樣做Android平臺也是OK的,不過個人感覺這裡可以不一致,由於這個邏輯在伺服器端,我並沒有驗證,方便的同學可以驗證下。

10.req.packageValue=”Sign=WXPay”,一般都是這樣寫死這個引數值。也有人說寫成req.packageValue=”prepay_id=” + prepayid,經測試Android兩種寫法都是可以調起微信支付的,至少最新版本SDK是可以的,以後則不清楚,官方也建議寫Sign=WXPay,據說iOS只支援這種寫法。

Android整合微信支付的出現-1等錯誤需要注意的要點

  1. 微信支付和支付寶支付是現在APP常用的支付方式,但是真正接入過兩種支付方式的猿友會很明顯的感覺到微信支付真心比支付寶麻煩很多,會出現很多莫名其妙的錯誤,但是官方的文件卻很難給出較好的解決方案。
  2. 前幾天公司的APP需要支付功能然後也需要這個-1問題,簡直感覺微信支付喪心病狂,這裡總結下自己出現的問題和一些其他網友出現的問題做個總結。
  3. reso.errCode = -1 官方的描述: -1 錯誤 可能的原因:簽名錯誤、未註冊APPID、專案設定APPID不正確、註冊的APPID與設定的不匹配、其他異常等。

銀聯支付:

先看流程圖

這裡寫圖片描述

大家不要被這張圖片搞懵逼的了,其實很簡單,這裡我將其分為5小步。

第一步:根據官方文件選擇符合自己的sdk

官方文件:

第二步:將相對應的.so檔案copy到 自己的工程裡面去。

特別注意:

.so檔案要放在src/main 目錄下,和Java檔案並行。還有就是把用到的許可權複製到自己專案中)

第三步: 和支付寶一樣,APP客戶端帶著這些訂單號向伺服器後臺請求訂單號orderNo

第四步:伺服器後臺接收到購買資訊之後,將資訊提交給銀聯後臺,銀聯接收到後臺之後給伺服器返回tn號

第五步:開啟呼叫銀聯支付。APP客戶端帶著這個流水號,也就是第三步中伺服器返回的tn號,呼叫銀聯SDK所提供的方法

注意

這個訂單流水號為21位純數字號;

呼叫方法: UPPayAssistEx.startPay(this, null, null, tn, mMode);

請求支付:

String serverMode = "01";
String tn="";// 從伺服器獲取的流水號
UPPayAssistEx.startPayByJAR(MainActivity.this, PayActivity.class, "", "", tn, serverMode);

tn值就是上面第三後臺給的tn,給到伺服器那裡

結果返回:

處理銀聯手機支付控制元件返回的支付結果。

呼叫銀聯支付後,返回app的時候用了,看返回結果傳,成功,失敗,或者是什麼返回。

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.e(TAG, "onActivityResult: ");
        if (data == null) {
            Log.e(TAG, "onActivityResult: 是空");
            return;
        }

        String str = data.getExtras().getString("pay_result");
        if (str.equalsIgnoreCase("success")) {
            Log.e(TAG, "onActivityResult: 支付成功!");
        } else if (str.equalsIgnoreCase("fail")) {
            Log.e(TAG, "onActivityResult: 支付失敗!");
        } else if (str.equalsIgnoreCase("cancel")) {
            Log.e(TAG, "onActivityResult: 支付取消!");
        }
    }

總感覺銀聯支付的SDK呼叫起來怪怪的,貌似回到了原始深林。