Android開發支付集成——支付寶集成

微信支付傳送門:http://www.javashuo.com/article/p-tdlguuff-n.html

 

 1、支付寶支付

1. 支付寶支付流程圖

支付寶支付流程

2. 集成前準備

  1. 去螞蟻金服註冊應用獲取appKey等信息
  2. 建立應用,添加APP支付功能
  3. 找到APP支付開發文檔,下載 SDK&Demo

3. 開始集成

  一、導入Demo中須要用到的Jar包html

    

  二、配置AndroidManifest.xml(這裏直接放經常使用的權限)java

  

 <!--所需權限-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

    <!--廣播跳轉-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!--百度地圖-->
    <!--百度地圖權限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

    <!--Mob分享-->
    <uses-permission android:name="android.permission.GET_TASKS" />
    <!-- 短信驗證登錄功能須要添加次權限來自動填充驗證碼,用不到能夠去掉 -->
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />


    <!--微信支付權限-->
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

    <!--支付寶支付權限-->
    <!-- 安卓讀寫sd權限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

支付回調android

<!--支付寶支付-->
        <!-- 支付寶H5頁面支付用的 -->
        <activity
            android:name="com.alipay.sdk.app.H5PayActivity"
            android:configChanges="orientation|keyboardHidden|navigation"
            android:exported="false"
            android:screenOrientation="behind" />
        <!-- 支付寶App支付頁面用的 -->
        <activity
            android:name="com.alipay.sdk.auth.AuthActivity"
            android:configChanges="orientation|keyboardHidden|navigation"
            android:exported="false"
            android:screenOrientation="behind" />

 

三、請求後臺接口拿到簽過名的信息(appKey,訂單信息等等),這裏我獲取數據,是直接給後臺傳遞的商品id,若是有的須要商品數量直接給傳給後臺,後臺根據id查詢出商品的信息,而後返回給前臺所須要的支付參數。ios

  支付寶返回參數用例(開始集成的時候看過好多博客都沒有返回參數數據結構,結果一臉懵逼,在這裏貼出,未加密以前的0.0):express

  

格式化後的:json

{
    "msg":"success",
    "code":200,
    "data":"alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=大家申請的app_id&biz_content=%7B%22out_trade_no%22%3A%22HY201806210002%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22subject%22%3A%22%E4%BC%98%E9%93%BA%E4%BC%9A%E5%91%98%E6%9C%8D%E5%8A%A1%E8%B4%B9%22%2C%22total_amount%22%3A%220.01%22%7D&charset=UTF-8&format=json&method=alipay.trade.app.pay&notify_url=http%3A%2F%2F大家的回調地址%2FaliPayCallBack%2FcallBack&sign=buipaoj2F8xl5XCAUVoJz%2Fbh8dHbaoRmdzoAEzqKRJqtZATT4bfFdzSHurAAL5C5gvntFrDTGHgNRGw%2BNZBtG4DfetOzcpHMAyjslrmUIMIr1YGC7Qya04mFBCh%2B0UIa1E7RISZWSbIVCHpZISknNgF2oTuTixNosXvDXzkGYGBUoaxdh1f6%2F%2Bw9lqKz7mkhsUc0x8lCeJHw4MnTS4gSLU%2BDmOCk6Tkiwb4Yv4Mz%2F6j7XReeagfX7qxs5qbObnnPX%2FFmu9T%2BF0LwJaPxr5Xys8kr8E4bhd4f7Y5FimXiw%2BG7EFkY0I69boiRob7zo%2BbWQ%2F53TAMeTXX5RJybEdXhrA%3D%3D&sign_type=RSA2&timestamp=2018-06-21+14%3A11%3A40&version=1.0",
    "status":"0"
}

後臺返回信息以後接下來就是咱們的事情了,調起支付寶進行支付api

 /*支付寶測試*/
    private void testZfbPay(final String key, final String value) {
        StringRequest stringRequest = new StringRequest(Request.Method.POST, NetWorkUrl.ZFBPAY, new Response.Listener<String>() {
            @RequiresApi(api = Build.VERSION_CODES.M)
            @Override
            public void onResponse(String s) {
                Log.e("GoPayOrderActivity", "-------getJson2-------" + s.toString());

                /*判斷code*/
                String code = (JSONObject.parseObject(s.toString()).getString("code"));

                if (code.equals("200")) {
                    String orderInfo = (JSONObject.parseObject(s.toString()).getString("data"));//返回的信息
                    MyALipayUtils.ALiPayBuilder builder = new MyALipayUtils.ALiPayBuilder();


                    builder.build().toALiPay(GoPayOrderActivity.this, orderInfo);
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {

            }
        }) {
            @Override
            public Map<String, String> getParams() throws AuthFailureError {
                Log.e("GoPayOrderActivity", "getParams:-----------------> " + userEntity.getPhone());

                Map<String, String> map = new HashMap<String, String>();
                map.put("account", userEntity.getPhone());
                map.put(key, value);
                map.put("token", userEntity.getToken());
                return map;
            }

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<String, String>();
                if (userEntity.getToken().equals("") && userEntity != null) {
                    headers.put("Authorization", userEntity.getToken());
                }
                return headers;
            }

        };
        /*設置請求一次*/
        stringRequest.setRetryPolicy(
                new DefaultRetryPolicy(
                        5000,//默認超時時間,應設置一個稍微大點兒的,例如本處的500000
                        DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//默認最大嘗試次數
                        DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
                )
        );
        AppApplication.getHttpQueues().add(stringRequest);/*請求數據*/
    }

MyALipayUtils.java這個類直接copy使用就能夠微信

/**
 * Created by dingchao on 2018/3/20.
 */

public class MyALipayUtils {
    private static final int SDK_PAY_FLAG = 1;
    private Activity context;
    private ALiPayBuilder builder;

    private MyALipayUtils(ALiPayBuilder builder) {
        this.builder = builder;
    }

    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {

//            返回碼    含義
//            9000    訂單支付成功
//            8000    正在處理中,支付結果未知(有可能已經支付成功),請查詢商戶訂單列表中訂單的支付狀態
//            4000    訂單支付失敗
//            5000    重複請求
//            6001    用戶中途取消
//            6002    網絡鏈接出錯
//            6004    支付結果未知(有可能已經支付成功),請查詢商戶訂單列表中訂單的支付狀態
//            其它    其它支付錯誤
            PayResult payResult = new PayResult((Map<String, String>) msg.obj);
            switch (payResult.getResultStatus()) {
                case "9000":
                    MobclickAgent.onEvent(context, "payment_success", "付款成功");
                    Toast.makeText(context, "支付成功", Toast.LENGTH_SHORT).show();
                    AppApplication.finishActivity();
                    context.finish();
//                    Toast.makeText(this, "支付成功", Toast.LENGTH_SHORT).show();
                    /*跳轉個人會員頁面*/
//                    Intent intent = new Intent(context, MyVipActivity.class);
//                    context.startActivity(intent);
                    break;
                case "8000":
                    Toast.makeText(context, "正在處理中", Toast.LENGTH_SHORT).show();
                    break;
                case "4000":
                    MobclickAgent.onEvent(context, "payment_fali", "付款失敗");
                    Toast.makeText(context, "訂單支付失敗", Toast.LENGTH_SHORT).show();
                    break;
                case "5000":
                    Toast.makeText(context, "重複請求", Toast.LENGTH_SHORT).show();
                    break;
                case "6001":
                    Toast.makeText(context, "已取消支付", Toast.LENGTH_SHORT).show();
                    break;
                case "6002":
                    Toast.makeText(context, "網絡鏈接出錯", Toast.LENGTH_SHORT).show();
                    break;
                case "6004":
                    Toast.makeText(context, "正在處理中", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    MobclickAgent.onEvent(context, "payment_fali", "付款失敗");
                    Toast.makeText(context, "支付失敗", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };

    /**
     * 簽名發在客戶端來作。
     *
     * @param context
     */
    public void toALiPay(final Activity context) {
        this.context = context;
        boolean rsa2 = (builder.getRsa2().length() > 0);
        Map<String, String> params = buildOrderParamMap(rsa2);
        String orderParam = buildOrderParam(params);
        String privateKey = rsa2 ? builder.getRsa2() : builder.getRsa();
        String sign = getSign(params, privateKey, rsa2);
        final String orderInfo = orderParam + "&" + sign;
        Log.e("chx", "toALiPay: " + orderInfo);
        Runnable payRunnable = new Runnable() {

            @Override
            public void run() {
                PayTask alipay = new PayTask(context);
                Map<String, String> result = alipay.payV2
                        (orderInfo, true);
                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };

        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }

    /**
     * 簽名在服務端來作
     *
     * @param context
     * @param orderInfo
     */
    public void toALiPay(final Activity context, final String orderInfo) {
        this.context = context;
        Runnable payRunnable = new Runnable() {

            @Override
            public void run() {
                PayTask alipay = new PayTask(context);
                Map<String, String> result = alipay.payV2
                        (orderInfo, true);
                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };

        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }

    /**
     * 構造支付訂單參數列表
     *
     * @param
     * @param
     * @return
     */
    private Map<String, String> buildOrderParamMap(boolean rsa2) {
        Map<String, String> keyValues = new HashMap<String, String>();

        keyValues.put("app_id", builder.appid);

        keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\"" + builder.money + "\",\"subject\":\"" + builder.title + "\",\"out_trade_no\":\"" + builder.orderTradeId + "\"}");

        keyValues.put("charset", "utf-8");

        keyValues.put("method", "alipay.trade.app.pay");
        //回調接口
        keyValues.put("notify_url", builder.getNotifyUrl());

        keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");

//        keyValues.put("timestamp", "2016-07-29 16:55:53");
        keyValues.put("timestamp", getCurrentTimeString());

        keyValues.put("version", "1.0");


        return keyValues;
    }

    /**
     * 構造支付訂單參數信息
     *
     * @param map 支付訂單參數
     * @return
     */
    private String buildOrderParam(Map<String, String> map) {
        List<String> keys = new ArrayList<String>(map.keySet());

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            sb.append(buildKeyValue(key, value, true));
            sb.append("&");
            Log.e("chx", "buildOrderParam: " + buildKeyValue(key, value, true));
        }

        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        sb.append(buildKeyValue(tailKey, tailValue, true));

        return sb.toString();
    }

    /**
     * 對支付參數信息進行簽名
     *
     * @param map 待簽名受權信息
     * @return
     */
    private String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {
        List<String> keys = new ArrayList<String>(map.keySet());
        // key排序
        Collections.sort(keys);

        StringBuilder authInfo = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            authInfo.append(buildKeyValue(key, value, false));
            authInfo.append("&");
        }

        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        authInfo.append(buildKeyValue(tailKey, tailValue, false));

        String oriSign = sign(authInfo.toString(), rsaKey, rsa2);
        String encodedSign = "";

        try {
            encodedSign = URLEncoder.encode(oriSign, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "sign=" + encodedSign;
    }

    private static final String ALGORITHM = "RSA";

    private static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";

    private static final String DEFAULT_CHARSET = "UTF-8";

    private String getAlgorithms(boolean rsa2) {
        return rsa2 ? SIGN_SHA256RSA_ALGORITHMS : SIGN_ALGORITHMS;
    }

    private String sign(String content, String privateKey, boolean rsa2) {
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
                    Base64.decode(privateKey));
            KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);

            java.security.Signature signature = java.security.Signature
                    .getInstance(getAlgorithms(rsa2));

            signature.initSign(priKey);
            signature.update(content.getBytes(DEFAULT_CHARSET));

            byte[] signed = signature.sign();

            return Base64.encode(signed);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 拼接鍵值對
     *
     * @param key
     * @param value
     * @param isEncode
     * @return
     */
    private String buildKeyValue(String key, String value, boolean isEncode) {
        StringBuilder sb = new StringBuilder();
        sb.append(key);
        sb.append("=");
        if (isEncode) {
            try {
                sb.append(URLEncoder.encode(value, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                sb.append(value);
            }
        } else {
            sb.append(value);
        }
        return sb.toString();
    }

    /**
     * 獲取當前日期字符串
     *
     * @return
     */
    private String getCurrentTimeString() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return df.format(new Date());
    }

    public static class ALiPayBuilder {
        private String rsa2 = "";
        private String rsa = "";
        private String appid;
        private String money;
        private String title;
        private String notifyUrl;
        private String orderTradeId;

        public MyALipayUtils build() {
            return new MyALipayUtils(this);
        }

        public String getOrderTradeId() {
            return orderTradeId;
        }

        public ALiPayBuilder setOrderTradeId(String orderTradeId) {
            this.orderTradeId = orderTradeId;
            return this;
        }

        public String getRsa2() {
            return rsa2;
        }

        public ALiPayBuilder setRsa2(String rsa2) {
            this.rsa2 = rsa2;
            return this;
        }

        public String getRsa() {
            return rsa;
        }

        public ALiPayBuilder setRsa(String rsa) {
            this.rsa = rsa;
            return this;
        }

        public String getAppid() {
            return appid;
        }

        public ALiPayBuilder setAppid(String appid) {
            this.appid = appid;
            return this;
        }

        public String getMoney() {
            return money;
        }

        public ALiPayBuilder setMoney(String money) {
            this.money = money;
            return this;
        }

        public String getTitle() {
            return title;
        }

        public ALiPayBuilder setTitle(String title) {
            this.title = title;
            return this;
        }

        public String getNotifyUrl() {
            return notifyUrl;
        }

        public ALiPayBuilder setNotifyUrl(String notifyUrl) {
            this.notifyUrl = notifyUrl;
            return this;
        }
    }
}

完成上述操做,你的app在螞蟻金服後臺應用上線以後,就徹底能夠調用支付了,可是在開發階段,應用沒有上線,你是不能進行調試的,因此支付寶有沙箱模式能夠進行調試,ios沒有喲網絡

進行沙箱調試在Activity的的onCreate()方法中添加數據結構

EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);//支付寶沙箱環境,正式需註釋

別忘了讓大家後臺把appKey等信息換成沙箱的,而後測試支付的時候,須要下載一個沙箱支付寶,這個你能夠隨意支付,附上連接

沙箱首頁:https://sandbox.alipaydev.com/user/accountDetails.htm?currentBar=1

App支付接入文檔:https://docs.open.alipay.com/204/105051

沙箱錢包下載:

調試都沒有問題以後,就能夠在螞蟻金服開發者平臺進行應用上線,而後沙箱代碼就能夠註釋了,這樣支付寶支付就接入完成

 若是問題或建議請發送到個人郵箱:dingchao7323@qq.com

相關文章
相關標籤/搜索