支付宝接入关键类说明
16lz
2021-01-26
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 = "2016083000128338"; /** 支付宝账户登录授权业务:入参pid值 */ public static final String PID = "2088502954592834"; /** 支付宝账户登录授权业务:入参target_id值 商户收款账号*///此处应该不起任何作用,下文无调用 public static final String TARGET_ID = ""; /** 商户私钥,pkcs8格式 */ /** 如下私钥,RSA2_PRIVATE 或者 RSA_PRIVATE 只需要填入一个 */ /** 如果商户两个都设置了,优先使用 RSA2_PRIVATE */ /** RSA2_PRIVATE 可以保证商户交易在更加安全的环境下进行,建议使用 RSA2_PRIVATE */ /** 获取 RSA2_PRIVATE,建议使用支付宝提供的公私钥生成工具生成, */ /** 工具地址:https://doc.open.alipay.com/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) msg.obj); /** 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。 */ String resultInfo = payResult.getResult();// 同步返回需要验证的信息。从支付结果中取到resultinfo String 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) msg.obj, true);//新建自定义的authResult对象 //利用Authresult中的自定义方法的到resultstatus 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 // 传入,则支付账户为该授权账户 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; } }; }; @Override protected 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,即包含支付订单信息的map Map 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() { @Override public void run() { //新建一个PAyTask对象 PayTask alipay = new PayTask(MainActivity.this); Map 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 authInfoMap = OrderInfoUtil2_0.buildAuthInfoMap(PID, APPID, TARGET_ID, rsa2); //利用这个方法,我可以将map解析成一个String类型的支付订单,即得到info String 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() { @Override public void run() { // 构造AuthTask 对象 AuthTask authTask = new AuthTask(MainActivity.this); // 调用授权接口,获取授权结果 Map 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 = "http://m.taobao.com"; // url可以是一号店或者淘宝等第三方的购物wap站点,在该网站的支付过程中,支付宝sdk完成拦截支付 extras.putString("url", url); intent.putExtras(extras); startActivity(intent); } @Override public void onClick(View v) { // TODO Auto-generated method stub }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
接下来是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 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;//返回处理过后的字符串 } @Override public 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; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
接下来是OrderInfoUtil2_0
package com.example.alipayinstense;import java.io.UnsupportedEncodingException;import java.net.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 buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) { Map keyValues = new HashMap(); // 商户签约拿到的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", rsa2 ? "RSA2" : "RSA"); return keyValues; } /** * 构造支付订单参数列表 * 就是说我这个支付订单是由这个map组成的,map中要有这些几个参数,并且给他们赋值 * @param pid * @param app_id * @param target_id * @return */ public static Map buildOrderParamMap(String app_id, boolean rsa2) { Map keyValues = new HashMap(); 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", "2016-07-29 16:55:53"); keyValues.put("version", "1.0"); return keyValues; } /** * 构造支付订单参数信息 * 传入进来一个Map参数,就是说利用这个方法,我可以将map解析成一个String类型的支付订单 * @param map * 支付订单参数 * @return */ public static String buildOrderParam(Map map) { List keys = new ArrayList(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 map, String rsaKey, boolean rsa2) { List keys = new ArrayList(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; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
利用最后两个类直接替换掉官方demo,会有意想不到的效果,你会发现PayDemoActivity的思路是那么的清晰。
看完这些全新的注释,是不是发现原来安卓应用支付宝开发原来很简单?
shirt!
更多相关文章
- 获取磁盘存储目录
- webview获取Url高度
- 将获取的html源代码格式化输出
- 35十包宽高
- Android判断网络是否连接
- Android中Java与JavaScript之间交互
- cocos2d-x获取设备信息
- android请求权限
- Android第十五天 ContentProvider之ContentResover