Android 支付开发(支付宝)

来源:互联网 发布:怎么找网络水军公司 编辑:程序博客网 时间:2024/05/21 23:31

支付宝更新了开发文档,针对最近的支付开发,做一下详细的开发流程总结。

一、接入流程

1.1、第一步:创建应用并获取APPID

创建应用,获取APPID,并且可以申请开通开放产品使用权限,通过APPID您的应用才能正常使用有权限调用的开放产品的接口能力。

具体参考:https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105308&docType=1

1.2、第二步:配置密钥

这一步可以找后台人员配置,也可以自己配置,具体不作详叙,需要用到的是支付宝私钥。

具体参考:https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105310&docType=1

1.3 第三部:集成并配置SDK

下载SDK,添加到项目中。
在商户应用工程的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" />

添加混淆:

-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 *;}

1.4、第四步:调用接口

这里写图片描述

这里看的很清晰,我们需要考虑的是2345678这几步即可。主要说一下获取的订单是签名后的订单信息,并没有将配置信息放在客户端来进行操作,这是为了安全性来考虑的。

构造交易数据并签名必须在商户服务端完成,商户的应用私钥绝对不能保存在商户APP客户端中,也不能从服务端下发。
同步返回的数据,只是一个简单的结果通知,商户确定该笔交易付款是否成功需要依赖服务端收到支付宝异步通知的结果进行判断。
商户系统接收到通知以后,必须通过验签(验证通知中的sign参数)来确保支付通知是由支付宝发送的。建议使用支付宝提供的SDK来完成

1.5、如何调用以及订单参数详解

这一步可以参考修改一下demo。

    public void payV2(View v) {        if (TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE)) {            new AlertDialog.Builder(this).setTitle("警告").setMessage("需要配置APPID | RSA_PRIVATE")                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {                        public void onClick(DialogInterface dialoginterface, int i) {                            //                            finish();                        }                    }).show();            return;        }        Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID);        String orderParam = OrderInfoUtil2_0.buildOrderParam(params);        String sign = OrderInfoUtil2_0.getSign(params, RSA_PRIVATE);        final String orderInfo = orderParam + "&" + sign;        Runnable payRunnable = new Runnable() {            @Override            public void run() {                PayTask alipay = new PayTask(PayDemoActivity.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();    }

支付行为需要在独立的非ui线程中执行。

支付结果获取和处理:

同步结果

private Handler mHandler = new Handler() {        public void handleMessage(Message msg) {            @SuppressWarnings("unchecked")                PayResult payResult = new PayResult((Map<String, String>) msg.obj);                /**                 * 同步返回的结果必须放置到服务端进行验证(验证的规则请看https://doc.open.alipay.com/doc2/                 * detail.htm?spm=0.0.0.0.xdvAU6&treeId=59&articleId=103665&                 * docType=1) 建议商户依赖异步通知                 */                String resultInfo = payResult.getResult();// 同步返回需要验证的信息                String resultStatus = payResult.getResultStatus();                // 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档                if (TextUtils.equals(resultStatus, "9000")) {                    Toast.makeText(PayDemoActivity.this, "支付成功", Toast.LENGTH_SHORT).show();                } else {                    // 判断resultStatus 为非"9000"则代表可能支付失败                    // "8000"代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)                    if (TextUtils.equals(resultStatus, "8000")) {                        Toast.makeText(PayDemoActivity.this, "支付结果确认中", Toast.LENGTH_SHORT).show();                    } else {                        // 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误                        Toast.makeText(PayDemoActivity.this, "支付失败", Toast.LENGTH_SHORT).show();                    }                }        };    };

异步结果:

在订单中返回一个key为notify_url的链接,支付宝会以POST方式调用notify_url传输数据。

支付参数:

Map<String, String> result = alipay.payV2(orderInfo, true);

orderInfo:加签后的订单信息,app支付请求参数字符串,主要包含商户的订单信息,key=value形式,以&连接。

true:boolean isShowPayLoading,加载过渡。

订单参数:

    public static Map<String, String> buildOrderParamMap(String app_id) {        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\":\"0.01\",\"subject\":\"1\",\"body\":\"我是测试数据\",\"out_trade_no\":\"" + getOutTradeNo() +  "\"}");        keyValues.put("charset", "utf-8");        keyValues.put("method", "alipay.trade.app.pay");        keyValues.put("sign_type", "RSA");        keyValues.put("timestamp", "2016-07-29 16:55:53");        keyValues.put("version", "1.0");        return keyValues;    }

包含公共参数和业务参数。biz_content是业务参数,其他均是公共参数。

这里写图片描述

这里虽然不是必须参数,但是还要具体配置,还是写上为好。毕竟别支付到别人账户去了哈哈!

订单加签流程:

  1. 请求参数按照key=value&key=value方式拼接的未签名原始字符串:
    /**     * 构造支付订单参数信息     *      * @param map     * 支付订单参数     * @return     */    public static 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("&");        }        String tailKey = keys.get(keys.size() - 1);        String tailValue = map.get(tailKey);        sb.append(buildKeyValue(tailKey, tailValue, true));        return sb.toString();    }
  1. 再对原始字符串进行签名
/**     * 对支付参数信息进行签名     *      * @param map     *            待签名授权信息     *      * @return     */    public static String getSign(Map<String, String> map, String rsaKey) {        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(), rsaKey);        String encodedSign = "";        try {            encodedSign = URLEncoder.encode(oriSign, "UTF-8");        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        }        return "sign=" + encodedSign;    }

具体参考:https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105351&docType=1

  1. 最后对请求字符串value进行encode,编码格式按请求串中的charset为准,没传charset按UTF-8处理,获得最终的请求字符串:
// 仅需对sign 做URL编码sign = URLEncoder.encode(sign, "UTF-8");

demo已经将2,3合并成一步。

支付结果验证:

当然,前面所述,基本支付功能不成问题,但是为了程序的严谨性和支付的安全性考虑,还是需要对支付结果进行验证。

同步通知验证:

示例:

{    "memo" : "xxxxx",    "result" : "{                    \"alipay_trade_wap_pay_response\":{                        \"code\":\"10000\",                        \"msg\":\"Success\",                        \"app_id\":\"2014072300007148\",                        \"out_trade_no\":\"081622560194853\",                        \"trade_no\":\"2016081621001004400236957647\",                        \"total_amount\":\"0.01\",                        \"seller_id\":\"2088702849871851\",                        \"charset\":\"utf-8\"                    },                    \"sign\":\"NGfStJf3i3ooWBuCDIQSumOpaGBcQz+aoAqyGh3W6EqA/gmyPYwLJ2REFijY9XPTApI9YglZyMw+ZMhd3kb0mh4RAXMrb6mekX4Zu8Nf6geOwIa9kLOnw0IMCjxi4abDIfXhxrXyj********\",                    \"sign_type\":\"RSA\"                }",    "resultStatus" : "9000"}

code结果码:

这里写图片描述

具体意思即验证返回结果信息跟订单信息是否一致,当然验证的参数也比较多
具体参考:
https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.1N7QWY&treeId=193&articleId=105302&docType=1

异步验证:
这里是服务端做的验证,支付成功后支付宝会吊起notify_url上的链接,返回支付参数,服务端对支付参数进行解析验证。

具体参考:
https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.q9gQhV&treeId=193&articleId=105301&docType=1

旧版支付当前还在兼容使用,当然需要使用旧版的SDK,具体需要注意的是

这里写图片描述

2 0