之前写了一个关于微信支付的博文,后来有人问我为什么不写上一个支付宝支付的呢。当初想的是支付宝支付比较简单,不像微信支付里面有很多坑,支付宝支付只是处理好异步回调就可以了,不过既然问到了,那我也写出来支付宝支付,同样还是比较简单,将东西都抽出来,方便调用。
首先是OrderInfoUtil2_0这个基础类。后面调用的很多方法都抽出来了集成在这个类里面,就当这个是一个工具类吧。
publicclassOrderInfoUtil2_0 {
/**
* 构造授权参数列表
*
* @param pid
* @param app_id
* @param target_id
* @return
*/
publicstaticMap buildAuthInfoMap(String pid, String app_id, String target_id) {
Map keyValues =newHashMap();
// 商户签约拿到的app_id,如:2013081700024223
keyValues.put("app_id", app_id);
// 商户签约拿到的pid,如:2088102123816631
keyValues.put("pid", pid);
// 服务接口名称, 固定值
keyValues.put("apiname","com.alipay.account.auth");
// 商户类型标识, 固定值
keyValues.put("app_name","mc");
// 业务类型, 固定值
keyValues.put("biz_type","openservice");
// 产品码, 固定值
keyValues.put("product_id","APP_FAST_LOGIN");
// 授权范围, 固定值
keyValues.put("scope","kuaijie");
// 商户唯一标识,如:kkkkk091125
keyValues.put("target_id", target_id);
// 授权类型, 固定值
keyValues.put("auth_type","AUTHACCOUNT");
// 签名类型
keyValues.put("sign_type","RSA");
returnkeyValues;
}
/**
* 构造支付订单参数列表
*
* @return
*/
publicstaticMap buildOrderParamMap(String app_id, String total_amount, String product_info, String time,String out_trade_no) {
Map keyValues =newHashMap();
keyValues.put("app_id", app_id);
keyValues.put("biz_content","{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\""+ total_amount +"\",\"subject\":\""+ product_info +"\",\"body\":\"兑换\",\"out_trade_no\":\""+out_trade_no +"\"}");
keyValues.put("charset","utf-8");
keyValues.put("method","alipay.trade.app.pay");
keyValues.put("sign_type","RSA");
keyValues.put("timestamp", time);// "2016-07-29 16:55:53"
keyValues.put("version","1.0");
keyValues.put("notify_url","成功回调地址");
returnkeyValues;
}
/**
* 构造支付订单参数信息
*
* @param map 支付订单参数
* @return
*/
publicstaticString buildOrderParam(Map map) {
List keys =newArrayList(map.keySet());
StringBuilder sb =newStringBuilder();
for(inti =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));
returnsb.toString();
}
/**
* 拼接键值对
*
* @param key
* @param value
* @param isEncode
* @return
*/
privatestaticString buildKeyValue(String key, String value,booleanisEncode) {
StringBuilder sb =newStringBuilder();
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);
}
returnsb.toString();
}
/**
* 对支付参数信息进行签名
*
* @param map 待签名授权信息
* @return
*/
publicstaticString getSign(Map map, String rsaKey) {
List keys =newArrayList(map.keySet());
// key排序
Collections.sort(keys);
StringBuilder authInfo =newStringBuilder();
for(inti =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
*/
privatestaticString getOutTradeNo() {
SimpleDateFormat format =newSimpleDateFormat("MMddHHmmss", Locale.getDefault());
Date date =newDate();
String key = format.format(date);
Random r =newRandom();
key = key + r.nextInt();
key = key.substring(0,15);
returnkey;
}
}
/**
* 重要说明:
*
* 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
*/
publicclassPayDemoActivityextendsFragmentActivity {
/**
* 支付宝支付业务:入参app_id
*/
publicstaticfinalString APPID ="入参app_id";
/**
* 支付宝账户登录授权业务:入参pid值
*/
publicstaticfinalString PID ="入参pid值";
/**
* 支付宝账户登录授权业务:入参target_id值
*/
publicstaticfinalString TARGET_ID ="入参target_id值";
/**
* 商户私钥,pkcs8格式
*/
publicstaticfinalString RSA_PRIVATE ="商户私钥";
privatestaticfinalintSDK_PAY_FLAG =1;
privatestaticfinalintSDK_AUTH_FLAG =2;
@SuppressLint("HandlerLeak")
privateHandler mHandler =newHandler() {
@SuppressWarnings("unused")
publicvoidhandleMessage(Message msg) {
switch(msg.what) {
caseSDK_PAY_FLAG: {
@SuppressWarnings("unchecked")
PayResult payResult =newPayResult((Map) msg.obj);
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为9000则代表支付成功
if(TextUtils.equals(resultStatus,"9000")) {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
MyToast.makeText(PayDemoActivity.this,"支付成功", Toast.LENGTH_SHORT).show();
}else{
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
MyToast.makeText(PayDemoActivity.this,"支付失败", Toast.LENGTH_SHORT).show();
}
break;
}
caseSDK_AUTH_FLAG: {
@SuppressWarnings("unchecked")
AuthResult authResult =newAuthResult((Map) msg.obj,true);
String resultStatus = authResult.getResultStatus();
// 判断resultStatus 为“9000”且result_code
// 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档
if(TextUtils.equals(resultStatus,"9000") && TextUtils.equals(authResult.getResultCode(),"200")) {
// 获取alipay_open_id,调支付时作为参数extern_token 的value
// 传入,则支付账户为该授权账户
MyToast.makeText(PayDemoActivity.this,
"授权成功\n"+ String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT)
.show();
}else{
// 其他状态值则为授权失败
MyToast.makeText(PayDemoActivity.this,
"授权失败"+ String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();
}
break;
}
default:
break;
}
}
;
};
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pay_main);
SimpleDateFormat dfs =newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date_e = dfs.format(newDate());
payV2("0.02","团币兑换", date_e);
}
/**
* 支付宝支付业务
*/
publicvoidpayV2(String price, String product_info, String time) {
if(TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE)) {
newAlertDialog.Builder(this).setTitle("警告").setMessage("需要配置APPID | RSA_PRIVATE")
.setPositiveButton("确定",newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialoginterface,inti) {
finish();
}
}).show();
return;
}
/**
* 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
*
* orderInfo的获取必须来自服务端;
*/
// Map params = OrderInfoUtil2_0.buildOrderParamMap(APPID, price, product_info, time);
Map params=newHashMap();
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
String sign = OrderInfoUtil2_0.getSign(params, RSA_PRIVATE);
finalString orderInfo = orderParam +"&"+ sign;
Runnable payRunnable =newRunnable() {
@Override
publicvoidrun() {
PayTask alipay =newPayTask(PayDemoActivity.this);
Map result = alipay.payV2(orderInfo,true);
Log.e("msp", result.toString());
Message msg =newMessage();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread =newThread(payRunnable);
payThread.start();
}
/**
* 支付宝账户授权业务
*
* @param v
*/
publicvoidauthV2(View v) {
if(TextUtils.isEmpty(PID) || TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE)
|| TextUtils.isEmpty(TARGET_ID)) {
newAlertDialog.Builder(this).setTitle("警告").setMessage("需要配置PARTNER |APP_ID| RSA_PRIVATE| TARGET_ID")
.setPositiveButton("确定",newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialoginterface,inti) {
}
}).show();
return;
}
/**
* 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
*
* authInfo的获取必须来自服务端;
*/
Map authInfoMap = OrderInfoUtil2_0.buildAuthInfoMap(PID, APPID, TARGET_ID);
String info = OrderInfoUtil2_0.buildOrderParam(authInfoMap);
String sign = OrderInfoUtil2_0.getSign(authInfoMap, RSA_PRIVATE);
finalString authInfo = info +"&"+ sign;
Runnable authRunnable =newRunnable() {
@Override
publicvoidrun() {
// 构造AuthTask 对象
AuthTask authTask =newAuthTask(PayDemoActivity.this);
// 调用授权接口,获取授权结果
Map result = authTask.authV2(authInfo,true);
Message msg =newMessage();
msg.what = SDK_AUTH_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必须异步调用
Thread authThread =newThread(authRunnable);
authThread.start();
}
/**
* get the sdk version. 获取SDK版本号
*/
publicvoidgetSDKVersion() {
PayTask payTask =newPayTask(this);
String version = payTask.getVersion();
MyToast.makeText(this, version, Toast.LENGTH_SHORT).show();
}
/**
* 原生的H5(手机网页版支付切natvie支付) 【对应页面网页支付按钮】
*
* @param v
*/
publicvoidh5Pay(View v) {
Intent intent =newIntent(this, H5PayDemoActivity.class);
Bundle extras =newBundle();
/**
* url是测试的网站,在app内部打开页面是基于webview打开的,demo中的webview是H5PayDemoActivity,
* demo中拦截url进行支付的逻辑是在H5PayDemoActivity中shouldOverrideUrlLoading方法实现,
* 商户可以根据自己的需求来实现
*/
String url ="http://m.taobao.com";
// url可以是一号店或者淘宝等第三方的购物wap站点,在该网站的支付过程中,支付宝sdk完成拦截支付
extras.putString("url", url);
intent.putExtras(extras);
startActivity(intent);
}
}
剩下就是支付宝支付的业务逻辑了。下面的out_trade_no是自己请求服务器返回过来的订单号,time就是当前时间,product_info就是显示在支付页面上的字段,自己设定,试试就知道。
/**
* 支付宝支付业务
*/
publicvoidpayV2(String price, String product_info, String time, String out_trade_no) {
if(TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE)) {
newAlertDialog.Builder(this).setTitle("警告").setMessage("需要配置APPID | RSA_PRIVATE")
.setPositiveButton("确定",newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialoginterface,inti) {
finish();
}
}).show();
return;
}
/**
* 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
*
* orderInfo的获取必须来自服务端;
*/
Map params = OrderInfoUtil2_0.buildOrderParamMap(APPID, price, product_info, time, out_trade_no);
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
String sign = OrderInfoUtil2_0.getSign(params, RSA_PRIVATE);
finalString orderInfo = orderParam +"&"+ sign;
Runnable payRunnable =newRunnable() {
@Override
publicvoidrun() {
PayTask alipay =newPayTask(RechargeMoneyActivity.this);
Map result = alipay.payV2(orderInfo,true);
Message msg =newMessage();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread =newThread(payRunnable);
payThread.start();
}
handler处理
[java]view plaincopy
privateHandler mHandler =newHandler() {
@SuppressWarnings("unused")
publicvoidhandleMessage(Message msg) {
switch(msg.what) {
caseSDK_PAY_FLAG: {
@SuppressWarnings("unchecked")
PayResult payResult =newPayResult((Map) msg.obj);
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String memo = payResult.getMemo();
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为9000则代表支付成功
if(TextUtils.equals(resultStatus,"9000")) {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
// showHintDialog("支付成功");
}else{
pay_state ="0";
}
String sign = TGmd5.getMD5(logid + pay_state + memo);
tuanbiExchangePresenter.doAlipay(logid, pay_state, memo, sign);
break;
}
caseSDK_AUTH_FLAG: {
@SuppressWarnings("unchecked")
AuthResult authResult =newAuthResult((Map) msg.obj,true);
String resultStatus = authResult.getResultStatus();
// 判断resultStatus 为“9000”且result_code
// 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档
if(TextUtils.equals(resultStatus,"9000") && TextUtils.equals(authResult.getResultCode(),"200")) {
// 获取alipay_open_id,调支付时作为参数extern_token 的value
// 传入,则支付账户为该授权账户
MyToast.makeText(RechargeMoneyActivity.this,
"授权成功\n"+ String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT)
.show();
}else{
// 其他状态值则为授权失败
MyToast.makeText(RechargeMoneyActivity.this,
"授权失败"+ String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();
}
break;
}
default:
break;
}
}
;
};
这样一个支付宝支付就集成了,是不是很简单。复制代码就能写出,注意里面代码注解。填写各种id。
csdn项目地址:http://blog.csdn.net/greatdaocaoren/article/details/75257603