1. 程式人生 > >android 集成支付寶app支付(原生態)-包括android前端與java後臺

android 集成支付寶app支付(原生態)-包括android前端與java後臺

請求 call 修改 quest ali log gif 操作 asm

本文講解了 android開發的原生態app集成了支付寶支付, 還提供了java後臺服務器處理支付寶支付的加密代碼, app前端與java後臺服務器使用json數據格式交互信息,java後臺服務主要用來對支付數據進行加密和接受支付寶服務器的回調

技術分享圖片

註意: 本文即涉及到 android前端, 也涉及到 Java後臺

準備條件:

  1. 到支付寶官網上註冊用戶, 打開開放平臺,支付寶默認生成沙箱環境,用來測試支付流程

  2. 安裝Android Studio【下載】, 安裝 Eclipse mars 【下載】, JDK1.7 tomcat7

1. 支付流程概述

使用過app支付的用戶都知道,在支付環節,如果選擇【支付寶支付】,我們的app會拉起支付寶app,並且將支付信息傳入到

支付寶app中顯示出來, 用戶確認付款完成付款操作, 有朋友就會問,那我們的應用邏輯應該放在哪個步驟呢?

步驟1: 應用程序拉起支付寶app前,會按照支付寶的規則傳遞相應的數據給支付寶,所以啟動支付寶前,我們需要構建數據, 基本數據包括商品描述,商品價錢等,但為了讓支付寶區別是哪個應用程序傳過來的數據,還需要AppId(應用程序在支付寶平臺上對應的序號); 另外為了保障數據不被篡改,我們傳遞的數據需要進行RSA加密

步驟2: 對數據的加密工作是放在後臺進行的,那為什麽不放在前臺呢,熟悉RSA加密的朋友都知道,RSA是非對稱加密,加密方與解密方 需要一對密鑰(公鑰和私鑰), 這些公鑰與私鑰是敏感信息,放在android端容易被盜取,所以將公鑰與私鑰放在後臺,後臺對數據加密完成後再傳給前臺

步驟3: 前臺將加密完成後的數據傳送給支付寶,由支付寶完成支付

步驟4: 支付完成後app端會得到相應的事件通知,前臺根據相應的事件來判斷前臺的業務走向

步驟5: 支付寶官方要求,使用支付寶完成支付後,支付寶後臺 會調用 應用服務的後臺用來告之交易支付是否真正成功

由於本地服務無法向外界提供服務, 所以支付寶回調本地測試的服務器接口無法連通,至於連通的方法,可以看一下

ngrok的配置, 這個工具可以穿透內網

2. Android端

項目運行後如下圖

技術分享圖片

2.1 下載導入項目到android studio中,將build.gradle中的storeFile的路徑設置正確

技術分享圖片

2.2 android端的通信使用 retrofit rxjava技術,所以訪問後臺的請求url需要配置正確, 如果使用本文提供的後臺,則可以不必修改,如果使用別人的後臺服務,需要進行更改

技術分享圖片

技術分享圖片

3.3 android端訪問後臺獲取加密數據,然後將加密數據傳遞給支付寶

註意:由於使用的支付寶的沙箱配置信息 ,必須加上 代碼 EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);

如果使用正式環境的支付寶配置信息, 不能加上上面沙箱代碼

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 private void aliPay(){ BizContent bizContent = new BizContent(); bizContent.setOut_trade_no(outTradeNum); bizContent.setTotal_amount(totalPrice); bizContent.setSubject("某個項目" + "-支付訂單"); String strBizContent = new Gson().toJson(bizContent); //generateOrderInfo去後臺獲取加密的信息 payService .generateOrderInfo(strBizContent) .subscribe(new Action1<String>() { @Override public void call(String s) { //orderInfo為加密的信息 final String orderInfo = s; Runnable payRunnable = new Runnable() { @Override public void run() { //沙箱環境開啟沙箱功能 //正式環境不需要下面這行代碼 EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX); PayTask alipay = new PayTask(MainActivity.this); Map<String, String> result = alipay.payV2(orderInfo, true); Log.i("msp", result.toString()); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; Thread payThread = new Thread(payRunnable); payThread.start(); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { showToast(throwable.getMessage()); } }); }

  

3.4 支付寶支付完成後執行 handleMessage

在handleMessage判斷支付情況, 如果 payResult.getResultStatus() == "9000" 則支付成功, 否則失敗

具體的失敗信息可以查看支付寶的官方文檔

技術分享圖片
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
    @SuppressWarnings("unused")
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SDK_PAY_FLAG: {
                @SuppressWarnings("unchecked")
                PayResult payResult = new PayResult((Map<String, String>) msg.obj);
                /**
                 對於支付結果,請商戶依賴服務端的異步通知結果。同步通知結果,僅作為支付結束的通知。
                 */
                String resultInfo = payResult.getResult();// 同步返回需要驗證的信息
                String resultStatus = payResult.getResultStatus();
                // 判斷resultStatus 為9000則代表支付成功
                if (TextUtils.equals(resultStatus, "9000")) {
                    outTradeNum = "";
                    showToast("支付成功");
                } else {
                    outTradeNum = "";
                    // 該筆訂單真實的支付結果,需要依賴服務端的異步通知。
                    Toast.makeText(MainActivity.this, "支付失敗", Toast.LENGTH_SHORT).show();
                }
                break;
            }
            case SDK_AUTH_FLAG: {
                @SuppressWarnings("unchecked")
                AuthResult authResult = new AuthResult((Map<String, String>) msg.obj, true);
                String resultStatus = authResult.getResultStatus();
 
                // 判斷resultStatus 為“9000”且result_code
                // 為“200”則代表授權成功,具體狀態碼代表含義可參考授權接口文檔
                if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) {
                    // 獲取alipay_open_id,調支付時作為參數extern_token 的value
                    // 傳入,則支付賬戶為該授權賬戶
                    Toast.makeText(MainActivity.this,
                            "授權成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT)
                            .show();
                } else {
                    // 其他狀態值則為授權失敗
                    Toast.makeText(MainActivity.this,
                            "授權失敗" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();
 
                }
                break;
            }
            default:
                break;
        }
    };
};
技術分享圖片

3. Java後臺

3.1 修改支付寶配置信息, 實例中使用的是本人支付寶中申請的沙箱配置信息

請將Config.properties中的信息改成自己的

技術分享圖片

3.2 generateOrderInfo對android傳遞的支付信息進行加密, 加密信息回傳給android端

技術分享圖片
@RequestMapping("/generateOrderInfo.htm")
    @ResponseBody
    public Result generateOrderInfo(String bizContent) 
    {
        Result result = new Result();
        AlipaySignature sing=  new AlipaySignature();
        if(StringUtils.isEmpty(bizContent)){
            result.setData("");
            result.setStateCode(Constant.RESULT_FAILURE);
            result.setDesc("待加簽字符串不能為空");
        }else
        {
            String appId = ConfigManager.getInstance().getConfigItem("APPID");
            Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(appId, bizContent, true);
            String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
 
            String privateKey = ConfigManager.getInstance().getConfigItem("ProjectPrivateKey");
            String sign = OrderInfoUtil2_0.getSign(params, privateKey, true);
            final String orderInfo = orderParam + "&" + sign;
            result.setDesc("加簽成功");
            result.setStateCode(Constant.RESULT_SUCCESS);
            result.setData(orderInfo);
        }
        return  result;
    }
技術分享圖片

3.3 支付成功後,支付寶服務端回調後臺應用程序接口,用來告之支付是否成功

技術分享圖片
/**
     * 支付寶的回調接口
     * @param request
     */
    @RequestMapping("/notifyOrderInfo.htm")
    public void notifyOrderInfo(HttpServletRequest request){
         
        if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
            Enumeration<?> pNames = request.getParameterNames();
            Map<String, String> param = new HashMap<String, String>();
            try {
                while (pNames.hasMoreElements()) {
                    String pName = (String) pNames.nextElement();
                    param.put(pName, request.getParameter(pName));
                }
 
                boolean signVerified = AlipaySignature.rsaCheckV1(param, ConfigManager.getInstance().getConfigItem("AlipayPublicKey"),
                        AlipayConstants.CHARSET_UTF8); // 校驗簽名是否正確
                if (signVerified) {
                    // TODO 驗簽成功後
                    // 按照支付結果異步通知中的描述,對支付結果中的業務內容進行1\2\3\4二次校驗,校驗成功後在response中返回success,校驗失敗返回failure
                    System.out.println("訂單支付成功:" + JSON.toJSONString(param)); 
                } else {
                    // TODO 驗簽失敗則記錄異常日誌,並在response中返回failure.
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return;
    }
技術分享圖片

關於支付寶的其它接口的更加詳細信息,請參照 【服務端詳解】

DEMO下載:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=844

android 集成支付寶app支付(原生態)-包括android前端與java後臺