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

对于初级开发者而言,吗德支付宝的开发文档最新版本和老版本写的一样狗屎的狠,网络上很多专家写的博客虽然有一点多余解释,但一个比一个惜字如金,来回调用的方法都看不懂有木有!更有甚者,有些大神完全脱离开发文档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 = "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<String, String>) 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<String, String>) 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<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() {

            @Override
            public 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类型的支付订单,即得到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<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 = "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<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;//返回处理过后的字符串
    }

    @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<String, String> buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) {
        Map<String, String> keyValues = new HashMap<String, String>();

        // 商户签约拿到的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<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", "2016-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;
    }

}

 
 
  • 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!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值