前言:
银联、微信支付都已经讲解过,今天写的是支付宝支付,支付宝支付应该是比较常用的了,在2016年8月份以后在支付宝平台申请得App支付都使用2.0的了,要搞清楚,不要导错包了。
一.支付宝支付资料下载和开发文档。
1.支付宝支付的开发文档:点击打开链接
2.支付宝sdk下载地址:点击打开链接
二.支付宝支付流程图:
三.支付宝资源导入和配置
1.把alipaySdk-20161222.jar复制到libs目录下,并添加依赖.
2.在AndroidManifest配置权限和配置支付宝控件。
<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" />
<!-- 支付宝 -->
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name="com.alipay.sdk.app.H5AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" />
1.订单数据的生成(这步可以在服务端完成,也可以在客户端)
在支付宝的demo有一个OrderInfoUtil2_0工具类,我们可以拷贝到我们自己的项目,该类是用来生成订单的。这个工具类,我进行了改动,可能跟支付宝Demo的不一样.
/**
* 构造支付订单参数列表
* @param app_id
* @return
*/
public static Map<String, String> buildOrderParamMap(String title,String body,String amount) {
Map<String, String> keyValues = new HashMap<String, String>();
keyValues.put("app_id", AppId)
keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\""+amount+"\",\"subject\":\""+title+"\", \"body\":\""+body+"\",\"out_trade_no\":\"" + getOutTradeNo()+ "\"}");
keyValues.put("charset", "utf-8");
keyValues.put("method", "alipay.trade.app.pay");
keyValues.put("notify_url", "这里填写支付宝支付成功的回调地址,需要服务端提供");
keyValues.put("sign_type", "RSA");
keyValues.put("timestamp", "2016-07-29 16:55:53");//这个日期可以自己生成
keyValues.put("version", "1.0");
return keyValues;
}
/**
* 构造支付订单参数信息
*
* @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 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();
}
/**
* 对支付参数信息进行签名
*
* @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;
}
/**
* 要求外部订单号必须唯一。
* @return
*/
private static 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);
return key;
}
2.调用buildOrderParamMap方法,传入标题,描述,金额构建订单。
Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap("订单标题","订单描述","金额");
把params 订单拼接成字符串(也可以在后台进行这个操作),注意,这里有个编码问题,在转成字符串时,会进行UTF-8编码,如果前端进行编码,服务端就无需再转码,注意,不然会出错。
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
3.把orderParam传给后台进行加签.(加签要放在服务端进行,不然很容易泄漏信息)
4.后台会返回一个加签后的字符串sign(个人命名),生成完整的符合支付宝支付的订单信息.
final String orderInfo = orderParam + "&" + sign;
注意:orderInfo大概是这样的
partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="测试"&body="测试测试"&total_fee="0.01"¬ify_url="http://notify.msp.hk/notify.htm"&service="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30m"&sign="lBBK%2F0w5LOajrMrji7DUgEqNjIhQbidR13GovA5r3TgIbNqv231yC1NksLdw%2Ba3JnfHXoXuet6XNNHtn7VE%2BeCoRO1O%2BR1KugLrQEZMtG5jmJIe2pbjm%2F3kb%2FuGkpG%2BwYQYI51%2BhA3YBbvZHVQBYveBqK%2Bh8mUyb7GM1HxWs9k4%3D"&sign_type="RSA"
5.最终,服务端会返回加签后的订单信息,我们可以发送一步请求去支付了
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(PayMentActivity.this);
Map<String, String> result = alipay.payV2(orderInfos, true);
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必须异步调用
Thread payThread = new Thread(payRunnable);
payThread.start();
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what) {
case SDK_PAY_FLAG: {
@SuppressWarnings("unchecked")
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, "9000")) {
ToastUtil.showShortToast(PayMentActivity.this,"用户支付成功");
} else if(TextUtils.equals(resultStatus,"6001")){
ToastUtil.showShortToast(PayMentActivity.this,"用户取消了支付");
} else {
ToastUtil.showShortToast(PayMentActivity.this,"用户支付失败");
}
break;
}
default:
break;
}
}
;
};
注意:java使用的是pack8格式的私钥,私钥不要暴露在客户端。
原创博客,转载请注明:
http://blog.csdn.NET/lgl5785592