Android 支付宝支付

之前写了一个关于微信支付的博文,后来有人问我为什么不写上一个支付宝支付的呢。当初想的是支付宝支付比较简单,不像微信支付里面有很多坑,支付宝支付只是处理好异步回调就可以了,不过既然问到了,那我也写出来支付宝支付,同样还是比较简单,将东西都抽出来,方便调用。

首先是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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容