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是业务参数,其他均是公共参数。
这里虽然不是必须参数,但是还要具体配置,还是写上为好。毕竟别支付到别人账户去了哈哈!
订单加签流程:
- 请求参数按照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(); }
- 再对原始字符串进行签名
/** * 对支付参数信息进行签名 * * @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
- 最后对请求字符串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,具体需要注意的是
- Android 支付开发(支付宝)
- Android 支付开发(支付宝)
- Android 支付宝支付开发
- android支付宝支付开发过程
- Android开发 接入支付宝移动支付
- android支付宝支付开发过程
- android支付宝支付开发过程
- Android支付宝支付开发流程
- Android 支付宝支付开发流程
- Android开发之微信支付,支付宝支付
- android支付宝支付
- Android 支付宝【支付】
- android 支付宝支付
- Android 支付宝支付
- Android支付宝支付
- android支付宝支付
- Android-支付宝支付
- Android支付宝支付
- 消息队列 的理解
- (转)在Mac下使用OpenCV, 在Xcode下使用OpenCV (非常基础,详细)
- POJ 2425 A Chess Game 博弈+有向无环图
- RandomUtils
- JS 转载:九个 Console 命令,让 js 调试更简单
- Android 支付开发(支付宝)
- 公司开发多个应用的时候是否可以使用同一个签名(*.jks)
- apk反编译工具的使用,超实用
- Spring Retry中文文档
- SVD分解
- Android 日志打印工具类 可显示打印所在的方法和行号
- js笔记 -- 最佳实践
- Android开发中---启动页面
- 常见IE6 bug兼容总结