zoukankan      html  css  js  c++  java
  • Android开发支付集成——支付宝集成

    微信支付传送门:https://www.cnblogs.com/dingxiansen/p/9209159.html

     一、支付宝支付

    1. 支付宝支付流程图

    支付宝支付流程

    2. 集成前准备

    1. 去蚂蚁金服注册应用获取appKey等信息
    2. 创建应用,添加APP支付功能
    3. 找到APP支付开发文档,下载 SDK&Demo

    3. 开始集成

      1、导入Demo中需要用到的Jar包

        

      2、配置AndroidManifest.xml(这里直接放常用的权限)

      

     <!--所需权限-->
        <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" />

    支付回调

    <!--支付宝支付-->
            <!-- 支付宝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" />

    3、请求后台接口拿到签过名的信息(appKey,订单信息等等),这里我获取数据,是直接给后台传递的商品id,如果有的需要商品数量直接给传给后台,后台根据id查询出商品的信息,然后返回给前台所需要的支付参数。

      支付宝返回参数用例(开始集成的时候看过好多博客都没有返回参数数据结构,结果一脸懵逼,在这里贴出,未加密之前的0.0):

      

    格式化后的:

    {
        "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"
    }

    后台返回信息之后接下来就是我们的事情了,调起支付宝进行支付

     /*支付宝测试*/
        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

        

  • 相关阅读:
    input 特殊字符限制
    angular $http服务
    angular $resouse服务
    ng-model-options 时延
    Pytorch之数据处理
    python 小顶堆
    刷题套路总结
    数组分成和尽可能相等的子数组
    python3.7 sorted 自定义排序
    Leetcode 二维数组周游 54
  • 原文地址:https://www.cnblogs.com/dingxiansen/p/9208949.html
Copyright © 2011-2022 走看看