1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 安卓应用接入支付宝支付功能步骤 真正做到完全翻译支付宝sdk开发应用

安卓应用接入支付宝支付功能步骤 真正做到完全翻译支付宝sdk开发应用

时间:2021-02-20 23:34:45

相关推荐

安卓应用接入支付宝支付功能步骤 真正做到完全翻译支付宝sdk开发应用

安卓应用接入支付宝支付功能步骤,真正做到完全翻译支付宝sdk开发应用

-02-19 12:25:15 [Android开发] 点击数:2450 作者:leerfun的博客 来源: 网络

对于初级开发者而言,吗德支付宝的开发文档最新版本和老版本写的一样狗屎的狠,网络上很多专家写的博客虽然有一点多余解释,但一个比一个惜字如金,来回调用的方法都看不懂有木有!更有甚者,有些大神完全脱离开发文档demo,自由发挥新篇章,浏览诸多,心有猛火。老子自己重新翻译支付表的开发文档!本文就是我怒火烧心后的产物,绝对完全剖析,Android在线支付Alipay(支付宝)开发,废话少说,上demo

package com.example.alipayinstense;import java.util.Map;import com.alipay.sdk.app.AuthTask;import com.alipay.sdk.app.PayTask;import android.annotation.SuppressLint;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v7.app.ActionBarActivity;import android.text.TextUtils;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;//这里的mainactivity就是官方的PayDemoActivity ;//里面的方法都在这里,就是类名不一样而已,大可不必纠结public class MainActivity extends ActionBarActivity implements OnClickListener {private TextView tv;private Button buy;/** 支付宝支付业务:入参app_id */public static final String APPID = "073000128438";/** 支付宝账户登录授权业务:入参pid值 */public static final String PID = "2088502952592834";/** 支付宝账户登录授权业务:入参target_id值 *///此处应该不起任何作用,下文无调用public static final String TARGET_ID = "";/** 商户私钥,pkcs8格式 *//** 如下私钥,RSA2_PRIVATE 或者 RSA_PRIVATE 只需要填入一个 *//** 如果商户两个都设置了,优先使用 RSA2_PRIVATE *//** RSA2_PRIVATE 可以保证商户交易在更加安全的环境下进行,建议使用 RSA2_PRIVATE *//** 获取 RSA2_PRIVATE,建议使用支付宝提供的公私钥生成工具生成, *//** 工具地址:https://doc./docs/doc.htm?treeId=291&articleId=106097&docType=1 *///公钥已上传至支付宝平台,私钥已保存本地,这是本应用私钥public static final String RSA2_PRIVATE = "MIIEvasefDA.....9w0BAQEFAASCBKYwgg....RUJCt7xt+EaJRCX/mGktAi5BQ4iwKTQea8PPDK9m+DzyfVECgYAtKMhyH...86CocnJrNqbtyoq......0pDStHa98LrihY+XeiyXUME6.....HBjey/..kBjmUb30PYdHU1OfTL3qHvy9MAE1U6GyOJgahZCPYHeqg==";//rsa没用public static final String RSA_PRIVATE = "";private static final int SDK_PAY_FLAG = 1;//sdk正常运行了吗?private static final int SDK_AUTH_FLAG = 2;//sdk确认了吗?private Activity activity;//这里声明一个活动是干什么的?private String orderNo;//订单详情@SuppressLint("HandlerLeak")private Handler mHandler = new Handler() {@SuppressWarnings("unused")public void handleMessage(Message msg) {switch (msg.what) {case SDK_PAY_FLAG: {//如果消息是 SDK正常运行@SuppressWarnings("unchecked")//将随该消息附带的msg.obj强转回map中,建立新的payresult支付结果PayResult payResult = new PayResult((Map<String, String>) msg.obj);/**对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。*/String resultInfo = payResult.getResult();// 同步返回需要验证的信息。从支付结果中取到resultinfoString resultStatus = payResult.getResultStatus();//得到resultstatus// 判断resultStatus 为9000则代表支付成功if (TextUtils.equals(resultStatus, "9000")) {// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();} else {// 该笔订单真实的支付结果,需要依赖服务端的异步通知。Toast.makeText(MainActivity.this, "支付失败", Toast.LENGTH_SHORT).show();}break;}case SDK_AUTH_FLAG: {//如果消息是SDK已经确认@SuppressWarnings("unchecked")//将随该消息附带的msg.obj强转回MAP,第二个参数为“去除消息中包含的括号吗?(boolean)”AuthResult authResult = new AuthResult((Map<String, String>) msg.obj, true);//新建自定义的authResult对象//利用Authresult中的自定义方法的到resultstatusString resultStatus = authResult.getResultStatus();// 判断resultStatus 为“9000”且result_code// 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) {// 获取alipay_open_id,调支付时作为参数extern_token 的value// 传入,则支付账户为该授权账户Toast.makeText(MainActivity.this,"授权成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();} else {// 其他状态值则为授权失败Toast.makeText(MainActivity.this,"授权失败" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();}break;}default:break;}};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//当前活动界面赋值initView();//初始化控件}private void initView() {// TODO Auto-generated method stub}/*** 支付宝pay方法* 支付宝支付业务* * @param v*/public void payV2(View v) {/*** 如果APPID是空值或私钥两个全是空,则弹出警告对话框告诉开发者“需要配置APPID|RSA_PRIVATE”*/if (TextUtils.isEmpty(APPID) || (TextUtils.isEmpty(RSA2_PRIVATE) && 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;}/*** 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险; * * orderInfo的获取必须来自服务端;防止本地orderInfo被认为更改,例如买个冰箱改成买个鸡蛋*/boolean rsa2 = (RSA2_PRIVATE.length() > 0);//rsa2私钥已经被赋值//在这里,传入APPID和私钥,得到请求map,即包含支付订单信息的mapMap<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID, rsa2);//将map解析成一个String类型的支付订单String orderParam = OrderInfoUtil2_0.buildOrderParam(params);//是rsa2类型的私钥吗?如果rsa2私钥已经被赋值,那么privateKey就被设置成rsa2,否则就被设置成rsa。这就是支付宝说的“如果你有俩私钥,优先使用RSa2私钥,靠!”String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;//对,privateKey就是商户私钥!通过此方法对商户的私钥进行“签名”处理,处理后就会生成(返回)一个sign=GKHJL%……&*的一大串字串String sign = OrderInfoUtil2_0.getSign(params, privateKey, rsa2);//最终,结合orderparam参数与sign签名字串,搞成orderInfo字串;final String orderInfo = orderParam + "&" + sign;//新开一个线程,将orderInfo字串传入到PayTask任务中去Runnable payRunnable = new Runnable() {@Overridepublic void run() {//新建一个PAyTask对象PayTask alipay = new PayTask(MainActivity.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();}/*** 支付宝账户授权业务* * @param v*/public void authV2(View v) {if (TextUtils.isEmpty(PID) || TextUtils.isEmpty(APPID)|| (TextUtils.isEmpty(RSA2_PRIVATE) && TextUtils.isEmpty(RSA_PRIVATE))|| TextUtils.isEmpty(TARGET_ID)) {new AlertDialog.Builder(this).setTitle("警告").setMessage("需要配置PARTNER |APP_ID| RSA_PRIVATE| TARGET_ID").setPositiveButton("确定", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialoginterface, int i) {}}).show();return;}/*** 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险; * * authInfo的获取必须来自服务端;*/boolean rsa2 = (RSA2_PRIVATE.length() > 0);Map<String, String> authInfoMap = OrderInfoUtil2_0.buildAuthInfoMap(PID, APPID, TARGET_ID, rsa2);//利用这个方法,我可以将map解析成一个String类型的支付订单,即得到infoString info = OrderInfoUtil2_0.buildOrderParam(authInfoMap);String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;//对支付参数信息进行签名 传入进来一个Map,一个rsaKey,//并且询问是否是rsa2格式的私钥 这个rsaKey是商户的私钥 就是说通过此方法对商户的私钥进行“签名”处理,//处理后就会生成(返回)一个sign=GKHJL%……&*的一大串字串String sign = OrderInfoUtil2_0.getSign(authInfoMap, privateKey, rsa2);final String authInfo = info + "&" + sign;//得到orderInfo后,我们开启新线程,发送相关信息Runnable authRunnable = new Runnable() {@Overridepublic void run() {// 构造AuthTask 对象AuthTask authTask = new AuthTask(MainActivity.this);// 调用授权接口,获取授权结果Map<String, String> result = authTask.authV2(authInfo, true);Message msg = new Message();msg.what = SDK_AUTH_FLAG;msg.obj = result;mHandler.sendMessage(msg);}};// 必须异步调用Thread authThread = new Thread(authRunnable);authThread.start();}/*** get the sdk version. 获取SDK版本号* */public void getSDKVersion() {PayTask payTask = new PayTask(this);String version = payTask.getVersion();Toast.makeText(this, version, Toast.LENGTH_SHORT).show();}/*** 原生的H5(手机网页版支付切natvie支付) 【对应页面网页支付按钮】* 意思就是我应用里面有一个h5的页面,页面里面有好多* 商品售卖,当我点击h5中的末一个商品支付时,支付表就会在此时调出来* 如果app中没有webView实现h5,那完全用不到此方法* * @param v*/public void h5Pay(View v) {Intent intent = new Intent(this, H5PayDemoActivity.class);Bundle extras = new Bundle();/*** url是测试的网站,在app内部打开页面是基于webview打开的,demo中的webview是H5PayDemoActivity,* demo中拦截url进行支付的逻辑是在H5PayDemoActivity中shouldOverrideUrlLoading方法实现,* 商户可以根据自己的需求来实现*/String url = "";// url可以是一号店或者淘宝等第三方的购物wap站点,在该网站的支付过程中,支付宝sdk完成拦截支付extras.putString("url", url);intent.putExtras(extras);startActivity(intent);}@Overridepublic void onClick(View v) {// TODO Auto-generated method stub}}

接下来是AuthResult类

package com.alipay.sdk.pay.demo;import java.util.Map;import android.text.TextUtils;/*** 确定结果* @author Administrator**/public class AuthResult {private String resultStatus;//结果状态private String result;//结果private String memo;//备忘录private String resultCode;//结果码private String authCode;//确认码private String alipayOpenId;//支付宝开放ID/*** 确认结果,参数为键值对全是string型的’结果行‘和一个boolean类型的参数'去除所有括号了吗'* @param rawResult* @param removeBrackets*/public AuthResult(Map<String, String> rawResult, boolean removeBrackets) {if (rawResult == null) {//传入的结果行map不为空才往下进行return;}for (String key : rawResult.keySet()) {if (TextUtils.equals(key, "resultStatus")) {//获取传入map中的键值对为resultStatus的值放入到resultStatus中(结果状态信息)resultStatus = rawResult.get(key);} else if (TextUtils.equals(key, "result")) {//获取传入map中的键值对的结果result = rawResult.get(key);} else if (TextUtils.equals(key, "memo")) {获取传入map中的备注(备忘录)memo = rawResult.get(key);}}String[] resultValue = result.split("&");//将结果用&符号拆分//对传入数组进行遍历for (String value : resultValue) {if (value.startsWith("alipay_open_id")) {//如果以alipay_open_id(支付宝开放id)开始的//此时的value是以alipay_open_id开头的值;支付宝的开放id=截取到的alipay_open_id字串去除括号alipayOpenId = removeBrackets(getValue("alipay_open_id=", value), removeBrackets);continue;}if (value.startsWith("auth_code")) {//如果循环进行到确认码"auth_code"authCode = removeBrackets(getValue("auth_code=", value), removeBrackets);//处理得到确认码continue;}if (value.startsWith("result_code")) {//如果解析到结果码resultCode = removeBrackets(getValue("result_code=", value), removeBrackets);//处理得到结果码continue;}}}/*** 移除括号的方法* @param str 传入的字符串* @param remove 移除吗?* @return 返回处理过后的字符串*/private String removeBrackets(String str, boolean remove) {if (remove) {//如果是移除的话if (!TextUtils.isEmpty(str)) {//如果传入的字符串不是空的话,则将对字串进行一下操作if (str.startsWith("\"")) {str = str.replaceFirst("\"", "");//移除第一个斜杠}if (str.endsWith("\"")) {str = str.substring(0, str.length() - 1);//移除最后的斜杠}}}return str;//返回处理过后的字符串}@Overridepublic String toString() {return "resultStatus={" + resultStatus + "};memo={" + memo + "};result={" + result + "}";}/*** 获取值得方法* @param header 头部字符串* @param data 数据字符串* @return */private String getValue(String header, String data) {return data.substring(header.length(), data.length());//将data从截取头部的长度处截取到传入data的末尾}/*** 获取String类型的结果状态* @return the resultStatus*/public String getResultStatus() {return resultStatus;}/*** 获取备注* @return the memo*/public String getMemo() {return memo;}/*** 获取结果* @return the result*/public String getResult() {return result;}/*** 获取结果码* @return the resultCode*/public String getResultCode() {return resultCode;}/*** 获取确认码* @return the authCode*/public String getAuthCode() {return authCode;}/*** 获取支付宝开放支付ID* @return the alipayOpenId*/public String getAlipayOpenId() {return alipayOpenId;}}

接下来是OrderInfoUtil2_0

package com.example.alipayinstense;import java.io.UnsupportedEncodingException;import .URLEncoder;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Collections;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Locale;import java.util.Map;import java.util.Random;public class OrderInfoUtil2_0 {/*** 自定义orderInfo请求信息对象* 构造授权参数列表* 列表里面的参数有PID,APPID,TARGETID,和一个boolean值“是否设置了rsa2私钥”* 就是说我这个支付参数map中要有这些参数,并且给他们赋值* @param pid* @param app_id* @param target_id* @return*/public static Map<String, String> buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) {Map<String, String> keyValues = new HashMap<String, String>();// 商户签约拿到的app_id,如:081700024223keyValues.put("app_id", app_id);// 商户签约拿到的pid,如:2088102123816631keyValues.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", rsa2 ? "RSA2" : "RSA");return keyValues;}/*** 构造支付订单参数列表* 就是说我这个支付订单是由这个map组成的,map中要有这些几个参数,并且给他们赋值* @param pid* @param app_id* @param target_id* @return*/public static Map<String, String> buildOrderParamMap(String app_id, boolean rsa2) {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", rsa2 ? "RSA2" : "RSA");//是rsa2私钥还是rsa私钥keyValues.put("timestamp", "-07-29 16:55:53");keyValues.put("version", "1.0");return keyValues;}/*** 构造支付订单参数信息* 传入进来一个Map参数,就是说利用这个方法,我可以将map解析成一个String类型的支付订单* @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();}/*** 拼接键值对* 将传入进来的两个字符串利用此方法拼接成key=value的形式* 该方法咨询是否转码(isEncode),如果需要对value进行转码的话,将会将其转为UTF—8格式;* @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();}/*** 对支付参数信息进行签名* 传入进来一个Map,一个rsaKey,并且询问是否是rsa2格式的私钥* 这个rsaKey是商户的私钥* 就是说通过此方法对商户的私钥进行“签名”处理,处理后就会生成(返回)一个sign=GKHJL%……&*的一大串字串* @param map* 待签名授权信息* * @return*/public static String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {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, rsa2);String encodedSign = "";try {encodedSign = URLEncoder.encode(oriSign, "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return "sign=" + encodedSign;}/*** 利用此方法获取到一个外部订单号"OutTradeNo"* 要求外部订单号必须唯一。* @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;}}

利用最后两个类直接替换掉官方demo,会有意想不到的效果,你会发现PayDemoActivity的思路是那么的清晰。

看完这些全新的注释,是不是发现原来安卓应用支付宝开发原来很简单?

shirt!

以上就是安卓应用接入支付宝支付功能步骤,真正做到完全翻译支付宝sdk开发应用的全文介绍,希望对您学习Android应用开发有所帮助.

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。