手機APP支付--整合支付寶支付控件

長話短說,本文根據支付寶官方說明文檔,簡單總結下,而且說明下開發過程碰到的問題以及該如何解決。html

 

整合步驟:android

1 登陸商家服務網站,下載開發包,地址:https://b.alipay.com/order/techService.htm, 下方選擇「移動支付」express

2 下載的開發包裏面包含整合文檔《支付寶錢包支付接口開發包2.0標準版.pdf》《支付寶錢包支付接口開發包2.0標準版接入與使用規則.pdf》安全

3 開發人員都請先看下《支付寶錢包支付接口開發包2.0標準版.pdf》 第2點交易流程:服務器

流程說明(以 Android 平臺爲例):
(1) 第 2 步 調用支付接口:此消息就是本接口所描述的開發包提供的支付對象
PayTask,將商戶訂單信息傳進pay方法喚起支付寶收銀臺,訂單格式具體參
見「5 請求參數說明」。
(2) 第 3 步:錢包支付開發包將會按照商戶 App 提供的參數發送支付請求。
(3) 第 5 步 : 異步發送支付通知: 錢包支付服務器端發送異步通知消息給商戶服務
器端,參見「7 服務器異步通知參數說明」。
(4) 第 7 步 接口返回支付結果:商戶應用客戶端經過當前調用支付的Activity的
Handler對象,經過它的回調函數獲取支付結果,參見「6 同步通知參數說
明」。app

 

(1) 構造訂單數據並簽名
商戶客戶端根據支付寶錢包支付開發包的接口規則, 經過程序生成獲得簽名結果及
要傳輸給支付寶錢包支付開發包的數據集合。
(2) 發送請求數據
把構造完成的數據集合傳遞給支付寶錢包支付開發包。
(3) 支付寶錢包支付開發包對請求數據進行處理
支付寶錢包支付開發包將請求數據根據業務規則包裝後傳遞給支付寶服務端, 服務
端獲得這些集合後, 會先進行安全校驗等驗證, 一系列驗證經過後便會處理完成這
次發送過來的數據請求。
(4) 返回處理的結果數據
對於處理完成的交易, 支付寶會以兩種方式把數據分別反饋給商戶應用和商戶服務
器。
? 在手機客戶端上,開發包客戶端直接把處理的數據結果反饋給商戶客戶端;
? 支付寶服務器主動發起通知,調用商戶在請求時設定好的頁面路徑(參數
notify_url,若是商戶沒設定,則不會進行該操做)。
(5) 對獲取的返回結果數據進行處理
商戶在客戶端同步通知接收模塊或服務端異步通知接收模塊獲取支付寶返回的結
果數據後,能夠結合商戶自身業務邏輯進行數據處理(如:訂單更新、自動充值到
會員帳號中等)。同步通知結果僅用於結果展現,入庫數據需以異步通知爲準。eclipse

4 關於交易流程其實跟銀聯支付大同小異,若是不明白能夠看下銀聯的交易流程:http://www.cnblogs.com/jager/p/4846376.html異步

5 理解完交易流程,接着建議先把開發包裏面官方提供的alipay_demo運行起來,而後就差很少成功一半了,demo裏面須要配置商戶PID,商戶收款帳號,商戶私鑰pkcs8格式,關於如何生成私鑰能夠參考:https://cshall.alipay.com/support/help_detail.htm?help_id=397433&keyword=%25C8%25E7%25BA%25CE%25C9%25FAide

6 接着看《支付寶錢包支付接口開發包2.0標準版接入與使用規則.pdf》5.2開發包集成流程函數

7 遇到沒法肯定的問題時,能夠諮詢支付寶客服 b.alipay.com/support/helperApply.htm?action=supportHome,而後點擊頁面右邊在線客服,諮詢技術問題。

 

直接上代碼:

首先是手機端的整合,整合其實文檔裏面已經寫的很是清楚了,這裏簡單總結下:

alipaySDK.jar 放到lib下面,並加入編譯路徑

在AndroidManifest.xml文件:

添加聲明
<
activity android:name="com.alipay.sdk.app.H5PayActivity" android:configChanges="orientation|keyboardHidden|navigation" android:exported="false" android:screenOrientation="behind" > </activity> <activity android:name="com.alipay.sdk.auth.AuthActivity" android:configChanges="orientation|keyboardHidden|navigation" android:exported="false" android:screenOrientation="behind" > </activity>
添加權限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
/>

工程的 proguard-project.txt 裏添加如下相關規則:

-libraryjars libs/alipaySDK-20150602.jar
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}

(添加規則我碰到個問題,就是app最後用簽名方式打包的時候會報錯,eclipse>android tools>export signd application pakage...,錯誤信息以下截圖,問了客服,目前這個問題還沒解決,若是有哪位大神解決了,請麻煩告訴我,這裏先謝了!)

目前,個人解決方案是屏蔽規則,暫時不使用(支付寶客服說沒問題)

上面就是大概的整合步驟,我的感受比銀聯簡單多了,銀聯整合請看http://www.cnblogs.com/jager/p/4846376.html

 

訂單數據生成:

/**
     * create the order info. 建立訂單信息
     * 
     */
    public String getOrderInfo(String subject, String body, String price) {

        // 簽約合做者身份ID
        String orderInfo = "partner=" + "\"" + PARTNER + "\"";

        // 簽約賣家支付寶帳號
        orderInfo += "&seller_id=" + "\"" + SELLER + "\"";

        // 商戶網站惟一訂單號
        orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";

        // 商品名稱
        orderInfo += "&subject=" + "\"" + subject + "\"";

        // 商品詳情
        orderInfo += "&body=" + "\"" + body + "\"";

        // 商品金額
        orderInfo += "&total_fee=" + "\"" + price + "\"";

        // 服務器異步通知頁面路徑
        orderInfo += "&notify_url=" + "\"" + "http://notify.msp.hk/notify.htm"
                + "\"";

        // 服務接口名稱, 固定值
        orderInfo += "&service=\"mobile.securitypay.pay\"";

        // 支付類型, 固定值
        orderInfo += "&payment_type=\"1\"";

        // 參數編碼, 固定值
        orderInfo += "&_input_charset=\"utf-8\"";

        // 設置未付款交易的超時時間
        // 默認30分鐘,一旦超時,該筆交易就會自動被關閉。
        // 取值範圍:1m~15d。
        // m-分鐘,h-小時,d-天,1c-當天(不管交易什麼時候建立,都在0點關閉)。
        // 該參數數值不接受小數點,如1.5h,可轉換爲90m。
        orderInfo += "&it_b_pay=\"30m\"";

        // extern_token爲通過快登受權獲取到的alipay_open_id,帶上此參數用戶將使用受權的帳戶進行支付
        // orderInfo += "&extern_token=" + "\"" + extern_token + "\"";

        // 支付寶處理完請求後,當前頁面跳轉到商戶指定頁面的路徑,可空
        orderInfo += "&return_url=\"m.alipay.com\"";

        // 調用銀行卡支付,需配置此參數,參與簽名, 固定值 (須要簽約《無線銀行卡快捷支付》才能使用)
        // orderInfo += "&paymethod=\"expressGateway\"";

        return orderInfo;
    }

 

支付接口調用(直接給出cordova插件應該怎麼寫,原生的其實同樣):

public class PayPlugin extends CordovaPlugin {

    @Override
    public boolean execute(String action, JSONArray args,
            CallbackContext callbackContext) throws JSONException {
        
        if(action.equals("unionPay")) {
            
            // 銀聯支付,00表示生產環境,01表示測試環境,配置成01後臺要修改相應的acp_sdk.properties
            String tn = args.getString(0);
            UPPayAssistEx.startPayByJAR(cordova.getActivity(), 
                     PayActivity.class, null, null, tn, "00");
             
        } else if(action.equals("aliPay")) {
            
            // 支付寶支付--orderInfo 就是從上面獲取的訂單信息
            String orderInfo = args.getString(0);
            
            // 對訂單作RSA 簽名
            String sign = sign(orderInfo);
            try {
                // 僅需對sign 作URL編碼
                sign = URLEncoder.encode(sign, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            // 完整的符合支付寶參數規範的訂單信息
            final String payInfo = orderInfo + "&sign=\"" + sign + "\"&"
                    + getSignType();
            
            Runnable payRunnable = new Runnable() {

                @Override
                public void run() {
                    // 構造PayTask 對象
                    PayTask alipay = new PayTask(cordova.getActivity());
                    // 調用支付接口,獲取支付結果
                    String result = alipay.pay(payInfo);

                    Message msg = new Message();
                    msg.what = SDK_PAY_FLAG;
                    msg.obj = result;
                    mHandler.sendMessage(msg);
                }
            };

            // 必須異步調用
            Thread payThread = new Thread(payRunnable);
            payThread.start();
            
        } 
        
        return super.execute(action, args, callbackContext);
    }

    private static final int SDK_PAY_FLAG = 1;
    private static final int SDK_CHECK_FLAG = 2;
    // 商戶私鑰,pkcs8格式
    // 如何生成:https://cshall.alipay.com/support/help_detail.htm?help_id=397433&keyword=%25C8%25E7%25BA%25CE%25C9%25FA
    public static final String RSA_PRIVATE = "XXX...XXX";

    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            
            Activity activity = cordova.getActivity();
            
            switch (msg.what) {
            case SDK_PAY_FLAG: {
                PayResult payResult = new PayResult((String) msg.obj);

                // 支付寶返回這次支付結果及加簽,建議對支付寶簽名信息拿簽約時支付寶提供的公鑰作驗籤
                String resultInfo = payResult.getResult();

                String resultStatus = payResult.getResultStatus();

                // 判斷resultStatus 爲「9000」則表明支付成功,具體狀態碼錶明含義可參考接口文檔
                if (TextUtils.equals(resultStatus, "9000")) {
                    Toast.makeText(activity, "支付成功",
                            Toast.LENGTH_SHORT).show();
                } else {
                    // 判斷resultStatus 爲非「9000」則表明可能支付失敗
                    // 「8000」表明支付結果由於支付渠道緣由或者系統緣由還在等待支付結果確認,最終交易是否成功以服務端異步通知爲準(小几率狀態)
                    if (TextUtils.equals(resultStatus, "8000")) {
                        Toast.makeText(activity, "支付結果確認中",
                                Toast.LENGTH_SHORT).show();

                    } else {
                        // 其餘值就能夠判斷爲支付失敗,包括用戶主動取消支付,或者系統返回的錯誤
                        Toast.makeText(activity, "支付失敗",
                                Toast.LENGTH_SHORT).show();

                    }
                }
                break;
            }
            case SDK_CHECK_FLAG: {
                Toast.makeText(activity, "檢查結果爲:" + msg.obj,
                        Toast.LENGTH_SHORT).show();
                break;
            }
            default:
                break;
            }
        };
    };
    
    /**
     * sign the order info. 對訂單信息進行簽名
     * 
     * @param content
     *            待簽名訂單信息
     */
    public String sign(String content) {
        return SignUtils.sign(content, RSA_PRIVATE);
    }

    /**
     * get the sign type we use. 獲取簽名方式--這個地方要注意跟下方的後臺解析裏面的簽名方式同樣,不然後臺isSign結果多是false,致使回調的時候簽名驗證失敗
     * 
     */
    public String getSignType() {
        return "sign_type=\"RSA\"";
    }

}

 

後臺回調方法實現:

 @ResponseBody
    @RequestMapping("/AlipayNotifyUrl")
    public void AlipayNotifyUrl(HttpServletRequest request,HttpServletResponse response){

        //System.out.println("----------------------支付寶服務器異步通知頁面路徑及處理");

        try{
            //獲取支付寶POST過來反饋信息
            Map<String,String> params = new HashMap<String,String>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                params.put(name, valueStr);
            }

            //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表(如下僅供參考)//
            //商戶訂單號
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //交易狀態
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

            //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表(以上僅供參考)//
            if(AlipayNotify.verify(params)){//驗證成功
                LogUtil.writeLog("驗證簽名結果[成功].====================>支付寶異步回調邏輯處理開始<==================回調返回內容:" + params.toString());
                if(trade_status.equalsIgnoreCase("TRADE_SUCCESS")){//交易成功
                    
                    // 這裏寫你的業務邏輯代碼。。
                }
                response.getOutputStream().print("success");
                LogUtil.writeLog("驗證簽名結果[成功].====================>支付寶異步回調邏輯處理結束<==================");
            }else{//驗證失敗
//             //校驗失敗不作任何處理
                LogUtil.writeLog("驗證簽名[失敗].====================>");
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

同銀聯支付同樣,爲了保證支付的成功以及完整性,通常後臺要配置個定時器來輪詢交易記錄,這裏就很少說,開發的時候要考量下相應的場景。

相關文章
相關標籤/搜索