记录自己的支付集成(微信&支付宝)

首先,作为一个菜鸟表示,虽然网上的集成框架很多,但是我要自己写,就算被坑的死去活来也要自己写。

1. 支付宝
这个支付宝的文档是个好东西,挺简单,挺容易看懂的,其次还有沙箱测试,表示支付宝一次通过很开心。 支付沙箱联调指南
首先导包,这里使用 20170710 的包,提前说明如果使用沙箱需要在支付的activity中添加
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
支付的账号和密码去沙箱中获取,支付沙箱联调指南页面的最下方,点击沙箱工具,跳转过后,页面左侧研发服务-沙箱账号

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pay);
        initView();
    }

这个直接上代码:ALiPay.java

public class AliPay {
    // 2017/7/20 沙盒测试通过 代码无误
    //支付宝支付业务:沙箱使用app_id
    public static final String APPID = "2016102200739552";
    //支付宝支付业务:沙箱使用RSA2_PRIVATE
    public static final String RSA2_PRIVATE = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCTci2x3b/OPT2ESK4+yZpBP7yQxxWdpB2Ht4XL7Vxa+Oa1je3lnnGImtAPsk9Z/LcgrMdg1mrjAP0cHUUHCVs8e70NR1P0YN6zFFDjZ/I4HWYUvAHAB0b/zPCT24xHbekIuyjpvTQKTRPu1QRPyCAlscJjVf6u0aUNh8tTsekxtS5tBOvQ5cm9kHw09XYaO+XtI39ocDj7rzTOkC1uQDfed2YZLXKVbiHm3WNJ71isL9bbC0nkjkBKRDTAGvyDTecvBy/mi8OnVJr9sg270UMNAtgTLONV0eKZp5JSuLwL0PGFXKc07OPb33Na/nsX9qpl6utjETNjJw2AatKMoVEpAgMBAAECggEAZyyXYwX7aHKb8Ev3ecISqaPS7DATJRso+sXl3vv6C0JuFg75sBp98Yv7GXC5bAuVjUy5uz5uzufrNVgZ7EGU0S747CjES5XZX9BQhcA/0xpnSwz/4IJ3IRokIiKX94emcFCe4Whe2PJ0h0QR3033iMjpcB9FtsjGSUCDe85bkkbYbpzTPiv0B5BQlkuSYPR5jR4aeURLJ4qDBiLF+pJHrNy9w0cxPEgKSpY6fusi9fEfs3dKq1a0TbgOMlpHE4ZlOqkjWZld9Z6yU6AYtxfhVzYeYobhPjicmf7cTahfYPYyP4zYfR3PrFOtTCSEOthyzr5TASZeXNMWmyuOb+jnjQKBgQDP4oXSwA7gVMiAk/P7SMRbyn4TEh97CJeWIRWAFJ8r8lCzBuNOMBNbjcsC+3kRdy8rFuFH3yjfKIo2Av/zYT/b441Xm9csVlHH7NLcRD6EYV1DLvgEEc4T+k8jmwRWeri+qzkyY2fH0X8ZdUdMvE271oMViyju5rgQClYMbzVViwKBgQC1kpEsnuXCds7CT89XUqX/nLSqTIfnejm9z/CnR7sPEISI8nQvdokTtyuRm9oV1LZqtN5Zj0Qqo+j3Gvmzgb0pw0sCVAYfmn4+ldicGYNkF1PNgPk8xlLwB395P6Fu8XbyQqlXuTrFVcTz0HWGdkAUuEuhFQgeD9OrqXXCA9BSmwKBgDYe/UQe6ECTEhgXbL+Q9D4Je8UvRK7dT8mwF07fD4l7bnMNagQjFAcT5TSDj8NySf9n14LEoHloroLdSRFt0hhHJ7cVRXGvj18DUuoxgi0oxAUHp1433HTrB8t3QivZi1tobF2n747gBbz1AXkC1SH/+OSU9DUuL+FNL5XRJgt9AoGAKq1kigRfJLIgLvPrXC8E7Wu72ztZxkKoR8EUY30sroHHZRj3ziAiYAvxpavoOrFgnvwcNxjBgPQ90bb5cgPQnnxUqRtuxQbfHX7DBw3IIEKLZAYojuxemiRpBeq62wTOXGrmusPC2JcsT9JzjUNGFJiszhPPcKFvsy2FjDCxSnkCgYEAt+BPODj5cV+aRKvMWdGAapPo/GOVBmQHTtNN/Cw7Lahg9sdunpbAGvyMxfosygnRKV+Ny7VDE4k9wRbm6bIu7esEj5pZv/5fuXU5yCGDNe04GbrUlTbo5Vmw2ChjppMFZSDQDheNn5wiPkTan9Rkx9mZeaHzrZZaKs2vAskKamI=";

    private static AliPay mAliPay;
    private Activity mContext;
    private PayListener mPayListener;
    private String orderTradeNo;

    private AliPay(Activity context) {
        mContext = context;
    }

    public static AliPay getInstance(Activity context) {
        if (mAliPay == null) {
            synchronized (AliPay.class) {
                if (mAliPay == null) {
                    mAliPay = new AliPay(context);
                }
            }
        }
        return mAliPay;
    }


    public void startAliPay(final String signOrderInfo, PayListener listener) {
        mPayListener = listener;
        Runnable payRunnable = new Runnable() {
            @Override
            public void run() {
                PayTask alipay = new PayTask(mContext);
                Map<String, String> result = alipay.payV2(signOrderInfo, true);
                Message msg = new Message();
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }


    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @SuppressWarnings("unchecked")
        public void handleMessage(Message msg) {
            PayResult payResult = new PayResult((Map<String, String>) msg.obj);

            String resultStatus = payResult.getResultStatus();
            String resultInfo = payResult.getResult();
            Log.i("resultinfo", resultInfo);

            if (mPayListener == null) {
                return;
            }
            // https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.xN1NnL&treeId=204&articleId=105302&docType=1
            if (payResult == null) {
                mPayListener.onPayError("结果解析错误");
                return;
            }
            if (TextUtils.equals(resultStatus, "9000")) {
                //支付成功
                mPayListener.onPaySuccess();
            } else if (TextUtils.equals(resultStatus, "8000")) {
                //正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
                mPayListener.onPayError("正在处理结果中");
            } else if (TextUtils.equals(resultStatus, "6001")) {
                //支付取消
                mPayListener.onPayCancel();
            } else if (TextUtils.equals(resultStatus, "6002")) {
                //网络连接出错
                mPayListener.onPayError("网络连接出错");
            } else if (TextUtils.equals(resultStatus, "4000")) {
                //支付错误
                mPayListener.onPayError("订单支付失败");
            } else {
                mPayListener.onPayError(resultInfo);
            }
        }
    };

    /**
     * 使用支付宝创建订单信息
     * 这个签名工作要放在后台服务器中进行处理
     * 前端将 付订单参数信息 上传到服务器 后台进行签名处理后,将签名后的订单信息发回来
     *
     * @param itemName
     * @param itemDescribe
     * @param itemPrice
     */
    public Map createOrderParamMap(String itemName, String itemDescribe, double itemPrice, String itemTradeNo) {
        //这里默认使用rsa2私钥
        Map<String, String> params = buildOrderParamMap(APPID, itemName, itemDescribe, itemPrice, itemTradeNo, true);
        return params;
    }

    public String createOrderInfo(Map<String, String> params) {
        return buildOrderParam(params);
    }

    /**
     * 构造支付订单参数列表
     *
     * @param app_id
     * @param itemName    商品名称
     * @param itemDecribe 商品详情
     * @param itemPrice   商品价格
     * @param rsa2        是否使用rsa2 建议true;
     * @return
     */
    private Map<String, String> buildOrderParamMap(String app_id, String itemName, String itemDecribe, double itemPrice, String itemTradeNo, boolean rsa2) {
        Map<String, String> keyValues = new HashMap<String, String>();

        keyValues.put("app_id", app_id);

        keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\"" + itemPrice + "\",\"subject\":\"" + itemName + "\",\"body\":\"" + itemDecribe + "\",\"out_trade_no\":\"" + itemTradeNo + "\"}");

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

        keyValues.put("method", "alipay.trade.app.pay");

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

        keyValues.put("timestamp", Comm.formatNowTime());

        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();
        StringBuilder s = 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("&");


            s.append(key);
            s.append("=");
            s.append(value);
            s.append("&");
        }

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


        s.append(tailKey);
        s.append("=");
        s.append(tailValue);
        Log.i("orderinfo",s.toString());
        return sb.toString();
    }

    /**
     * 拼接键值对
     *
     * @param key
     * @param value
     * @param isEncode
     * @return
     */
    private static 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
     */
    public String getOutTradeNo() {
        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
        Date date = new Date();
        String key = format.format(date);
        Random r = new Random();
        key = key + r.nextInt();
        key = key.substring(0, 15);
        orderTradeNo = key;
        return key;
    }

    /**
     * 对支付参数信息进行签名
     *
     * @param map 待签名授权信息
     * @return
     */
    public String getSign(Map<String, String> map) {
        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 = SignUtils.sign(authInfo.toString(), RSA2_PRIVATE, true);
        String encodedSign = "";

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

然后自定义一个支付结果接口: PayListener

public interface PayListener {
    //支付成功
    void onPaySuccess();

    //支付失败
    void onPayError(String resultStatus);

    //支付取消
    void onPayCancel();
}

然后调用:
注意:
1、这里的signOrderInfo必须要从服务器获取,我的后台这里还是给力的,上传订单id就把signOrderInfo传过来了,都不用自己写,多亏了我的口才。
2、这里的orderInfo是是进行 URLEncoder.encode() 转码的(键为原文,值进行转码),具体内容可以打印出来看下,然后加密sign内容是使用原文(没有进行转码)进行加密
3、这里的Base64.java PayResult.java SignUtils.java 去支付宝的demo中获取(测试阶段)
这里的Base64.java PayResult.java SignUtils.java 去支付宝的demo中获取(测试阶段)
这里的Base64.java PayResult.java SignUtils.java 去支付宝的demo中获取(测试阶段)

这里就是Demo的下载地址了 https://docs.open.alipay.com/54/104509

自己测试的时候可以这么写:

AliPay aliPay = AliPay.getInstance(this);
Map orderParamMap = aliPay.createOrderParamMap("商品名字", "商品描述", 0.01, "123123123123123");
String orderInfo = aliPay.createOrderInfo(orderParamMap);
String sign = aliPay.getSign(orderParamMap);
String signOrderInfo = orderInfo + "&" + sign;

AliPay.getInstance(PayActivity.this).startAliPay(signOrderInfo, new PayListener() {
                                @Override
                                public void onPaySuccess() {
                                    Comm.Tip(mContext, "支付成功");
                                }

                                @Override
                                public void onPayError(String resultStatus) {
                                    Comm.Tip(mContext, "支付失败");
                                }

                                @Override
                                public void onPayCancel() {
                                    Comm.Tip(mContext, "支付取消");
                                }
                            });

2.微信支付
微信支付满满的都是坑,特别是官方Demo,看的我头晕,然后还是没弄好,很尴尬。
首先注意一个大坑:我们后台申请接入时候签名填写错误,我就想说ios没有签名,安卓要签名,然后导致了ios成功,安卓失败,我找了一下午的原因。
注意:微信开发平台的申请的应用签名,如果在手机上安装debug包获取的签名,那么只能debug包才能调用微信支付,如果是release包获取的签名,那么只有release包才能调用微信支付,当然,微信开发平台上的签名和包名都是可以更换的。
首先导个包,gradle方式也可以,然而我用AS下不下来,只好导包
简单粗暴上代码:WechatPay.java

public class WechatPay {
    private static WechatPay wechatPay;
    private Context mContext;
    private IWXAPI mIWXAPI;
    private PayListener mPayListener;

    private WechatPay(Activity context) {
        mContext = context;
    }

    public static WechatPay getInstance(Activity context) {
        if (wechatPay == null) {
            synchronized (WechatPay.class) {
                if (wechatPay == null) {
                    wechatPay = new WechatPay(context);
                }
            }
        }
        return wechatPay;
    }

    /**
     * 初始化微信支付接口
     *
     * @param appId
     */
    public void init(String appId) {
        mIWXAPI = WXAPIFactory.createWXAPI(mContext, null);
        mIWXAPI.registerApp(appId);
    }

    /**
     * 获取微信接口
     *
     * @return
     */
    public IWXAPI getWXApi() {
        return mIWXAPI;
    }

    /**
     * 调起支付
     *
     * @param appId
     * @param partnerId
     * @param prepayId
     * @param nonceStr
     * @param timeStamp
     * @param sign
     */
    public void startWeChatPay(String appId, String partnerId, String prepayId,
                               String nonceStr, String timeStamp, String sign, PayListener listener) {
        mPayListener = listener;
        init(appId);
        if (!checkWx()) {
            if (listener != null) {
                listener.onPayError("未安装微信或者微信版本过低");
            }
            return;
        }
        PayReq request = new PayReq();
        request.appId = appId;
        request.partnerId = partnerId;
        request.prepayId = prepayId;
        request.packageValue = "Sign=WXPay";
        request.nonceStr = nonceStr;
        request.timeStamp = timeStamp;
        request.sign = sign;
        mIWXAPI.sendReq(request);
    }


    /**
     * 响应支付回调
     *
     * @param error_code
     * @param message
     */
    public void onResp(int error_code, String message) {
        if (error_code == 0) {
            //支付成功
            mPayListener.onPaySuccess();
        } else if (error_code == -1) {
            //支付异常
            mPayListener.onPayError(message);
        } else if (error_code == -2) {
            //支付取消
            mPayListener.onPayCancel();
        }
        mPayListener = null;
    }


    //检测微信客户端是否支持微信支付
    private boolean checkWx() {
        return isWeixinAvilible() && mIWXAPI.isWXAppInstalled() && mIWXAPI.getWXAppSupportAPI() >= Build.PAY_SUPPORTED_SDK_INT;
    }

    /**
     * 判断微信是否安装
     *
     * @return
     */
    private boolean isWeixinAvilible() {
        return appIsAvilible("com.tencent.mm");
    }

    /**
     * 判断app是否安装
     *
     * @param packageName
     * @return
     */
    private boolean appIsAvilible(String packageName) {
        final PackageManager packageManager = mContext.getPackageManager();// 获取packagemanager
        List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);// 获取所有已安装程序的包信息
        if (pinfo != null) {
            for (int i = 0; i < pinfo.size(); i++) {
                String pn = pinfo.get(i).packageName;
                if (pn.equals(packageName)) {
                    return true;
                }
            }
        }
        return false;
    }
}

其次是:WXPayEntryActivity .java

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (WechatPay.getInstance(this) != null) {
            WechatPay.getInstance(this).getWXApi().handleIntent(getIntent(), this);
        } else {
            finish();
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        if (WechatPay.getInstance(this) != null) {
            WechatPay.getInstance(this).getWXApi().handleIntent(intent, this);
        }
    }

    @Override
    public void onReq(BaseReq baseReq) {

    }

    @Override
    public void onResp(BaseResp baseResp) {
        if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
            if (WechatPay.getInstance(this) != null) {
                WechatPay.getInstance(this).onResp(baseResp.errCode, baseResp.errStr);
                finish();
            }
        }
    }
}

再来清单文件中:
改下第二行和最后一行的地址

<!-- 微信 -->
        <activity
            android:name=".Controller.wxapi.WXPayEntryActivity"
            android:configChanges="orientation|keyboardHidden|navigation|screenSize"
            android:launchMode="singleTop"
            android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
        <activity-alias
            android:name=".wxapi.WXPayEntryActivity"
            android:exported="true"
            android:targetActivity=".Controller.wxapi.WXPayEntryActivity"/>

好的,现在开始调用:
我的order类当然也是后台发给我的喽

 WechatPay.getInstance(PayActivity.this).startWeChatPay(order.getAppid(), order.getPartid(), order.getPrepayid(), order.getNoncestr(), order.getTimestamp(), order.getSign(), new PayListener() {
                                @Override
                                public void onPaySuccess() {
                                    Comm.Tip(mContext, "支付成功");
                                }

                                @Override
                                public void onPayError(String resultStatus) {
                                    Comm.Tip(mContext, "支付失败");
                                }

                                @Override
                                public void onPayCancel() {
                                    Comm.Tip(mContext, "支付取消");
                                }
                            });

好的,打完收工,完成之后发现,其实也就是那么回事。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值