支付宝通用类封装

在做Android支付的时候肯定会用到支付宝支付, 根据官方给出的demo做起来非常费劲,所以我们需要一次简单的封装。封装的代码也很简单,就是将官网给的demo提取出一个类来方便使用。

1<span style="font-size: medium;">/**
2 * 支付宝支付
3 *
4 * @author lenovo
5 */
6public class Alipay {
7  // 商户PID
8  public static final String PARTNER = "123456789";
9  // 商户收款账号
10  public static final String SELLER = "qibin0506@gmail.com";
11  // 商户私钥,pkcs8格式
12  public static final String RSA_PRIVATE = "rsa_private";
13  // 支付宝公钥
14  public static final String RSA_PUBLIC = "rsa_public";
15  private static final int SDK_PAY_FLAG = 1;
16  private WeakReference<Activity> mActivity;
17  private OnAlipayListener mListener;
18  public Alipay(Activity activity) {
19    mActivity = new WeakReference<Activity>(activity);
20  }
21  @SuppressLint("HandlerLeak")
22  private Handler mHandler = new Handler() {
23    public void handleMessage(Message msg) {
24      if (msg.what == SDK_PAY_FLAG) {
25        PayResult payResult = new PayResult((String) msg.obj);
26        // 支付宝返回此次支付结果及加签,建议对支付宝签名信息拿签约时支付宝提供的公钥做验签
27        String resultInfo = payResult.getResult();
28        String resultStatus = payResult.getResultStatus();
29        // 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档
30        if (TextUtils.equals(resultStatus, "9000")) {
31          if (mListener != null) mListener.onSuccess();
32        } else {
33          // 判断resultStatus 为非“9000”则代表可能支付失败
34          // “8000”代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,
35          // 最终交易是否成功以服务端异步通知为准(小概率状态)
36          if (TextUtils.equals(resultStatus, "8000")) {
37            if (mListener != null) mListener.onWait();
38          } else {
39            // 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误
40            if (mListener != null) mListener.onCancel();
41          }
42        }
43      }
44    }
45  };
46  /**
47   * 支付
48   *
49   * @param title   标题 不能为空或者“”
50   * @param desc  描述 不能为空或者“”
51   * @param price 价格 不能为空或者“”
52   * @param sn  商品唯一货号 不能为空或者“”
53   * @param url 服务器回调url 不能为空或者“”
54   */
55  public void pay(String title, String desc, String price, String sn, String url) {
56    // 订单
57    String orderInfo = getOrderInfo(title, desc, price, sn, url);
58    // 对订单做RSA 签名
59    String sign = sign(orderInfo);
60    try {
61      // 仅需对sign 做URL编码
62      sign = URLEncoder.encode(sign, "UTF-8");
63    } catch (UnsupportedEncodingException e) {
64      e.printStackTrace();
65    }
66    // 完整的符合支付宝参数规范的订单信息
67    final String payInfo = orderInfo + "&sign=/"" + sign + "/"&"
68        + getSignType();
69    Runnable payRunnable = new Runnable() {
70      @Override
71      public void run() {
72        Activity activity = mActivity.get();
73        if(activity == null) return;
74        // 构造PayTask 对象
75        PayTask alipay = new PayTask(activity);
76        // 调用支付接口,获取支付结果
77        String result = alipay.pay(payInfo);
78        Message msg = new Message();
79        msg.what = SDK_PAY_FLAG;
80        msg.obj = result;
81        mHandler.sendMessage(msg);
82      }
83    };
84    // 必须异步调用
85    Thread payThread = new Thread(payRunnable);
86    payThread.start();
87  }
88  /**
89   * create the order info. 创建订单信息
90   *
91   */
92  public String getOrderInfo(String subject, String body, String price,
93      String sn, String url) {
94    // 签约合作者身份ID
95    String orderInfo = "partner=" + "/"" + PARTNER + "/"";
96    // 签约卖家支付宝账号
97    orderInfo += "&seller_id=" + "/"" + SELLER + "/"";
98    // 商户网站唯一订单号
99    orderInfo += "&out_trade_no=" + "/"" + sn + "/"";
100    // 商品名称
101    orderInfo += "&subject=" + "/"" + subject + "/"";
102    // 商品详情
103    orderInfo += "&body=" + "/"" + body + "/"";
104    // 商品金额
105    orderInfo += "&total_fee=" + "/"" + price + "/"";
106    // 服务器异步通知页面路径
107    orderInfo += "¬ify_url=" + "/"" + url + "/"";
108    // 服务接口名称, 固定值
109    orderInfo += "&service=/"mobile.securitypay.pay/"";
110    // 支付类型, 固定值
111    orderInfo += "&payment_type=/"1/"";
112    // 参数编码, 固定值
113    orderInfo += "&_input_charset=/"utf-8/"";
114    // 设置未付款交易的超时时间
115    // 默认30分钟,一旦超时,该笔交易就会自动被关闭。
116    // 取值范围:1m~15d。
117    // m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
118    // 该参数数值不接受小数点,如1.5h,可转换为90m。
119    orderInfo += "&it_b_pay=/"30m/"";
120    // extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
121    // orderInfo += "&extern_token=" + "/"" + extern_token + "/"";
122    // 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
123    orderInfo += "&return_url=/"m.alipay.com/"";
124    // 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
125    // orderInfo += "&paymethod=/"expressGateway/"";
126    return orderInfo;
127  }
128  /**
129   * sign the order info. 对订单信息进行签名
130   *
131   * @param content
132   *            待签名订单信息
133   */
134  public String sign(String content) {
135    return SignUtils.sign(content, RSA_PRIVATE);
136  }
137  /**
138   * get the sign type we use. 获取签名方式
139   *
140   */
141  public String getSignType() {
142    return "sign_type=/"RSA/"";
143  }
144  public void setListener(OnAlipayListener l) {
145    mListener = l;
146  }
147  /**
148   * 支付回调接口
149   *
150   * @author lenovo
151   *
152   */
153  public static class OnAlipayListener {
154    /**
155     * 支付成功
156     */
157    public void onSuccess() {}
158    /**
159     * 支付取消
160     */
161    public void onCancel() {}
162    /**
163     * 等待确认
164     */
165    public void onWait() {}
166  }
167}
168final class Base64 {
169  private static final int BASELENGTH = 128;
170  private static final int LOOKUPLENGTH = 64;
171  private static final int TWENTYFOURBITGROUP = 24;
172  private static final int EIGHTBIT = 8;
173  private static final int SIXTEENBIT = 16;
174  private static final int FOURBYTE = 4;
175  private static final int SIGN = -128;
176  private static char PAD = '=';
177  private static byte[] base64Alphabet = new byte[BASELENGTH];
178  private static char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
179  static {
180    for (int i = 0; i < BASELENGTH; ++i) {
181      base64Alphabet[i] = -1;
182    }
183    for (int i = 'Z'; i >= 'A'; i--) {
184      base64Alphabet[i] = (byte) (i - 'A');
185    }
186    for (int i = 'z'; i >= 'a'; i--) {
187      base64Alphabet[i] = (byte) (i - 'a' + 26);
188    }
189    for (int i = '9'; i >= '0'; i--) {
190      base64Alphabet[i] = (byte) (i - '0' + 52);
191    }
192    base64Alphabet['+'] = 62;
193    base64Alphabet['/'] = 63;
194    for (int i = 0; i <= 25; i++) {
195      lookUpBase64Alphabet[i] = (char) ('A' + i);
196    }
197    for (int i = 26, j = 0; i <= 51; i++, j++) {
198      lookUpBase64Alphabet[i] = (char) ('a' + j);
199    }
200    for (int i = 52, j = 0; i <= 61; i++, j++) {
201      lookUpBase64Alphabet[i] = (char) ('0' + j);
202    }
203    lookUpBase64Alphabet[62] = (char) '+';
204    lookUpBase64Alphabet[63] = (char) '/';
205  }
206  private static boolean isWhiteSpace(char octect) {
207    return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
208  }
209  private static boolean isPad(char octect) {
210    return (octect == PAD);
211  }
212  private static boolean isData(char octect) {
213    return (octect < BASELENGTH && base64Alphabet[octect] != -1);
214  }
215  /**
216   * Encodes hex octects into Base64
217   *
218   * @param binaryData
219   *            Array containing binaryData
220   * @return Encoded Base64 array
221   */
222  public static String encode(byte[] binaryData) {
223    if (binaryData == null) {
224      return null;
225    }
226    int lengthDataBits = binaryData.length * EIGHTBIT;
227    if (lengthDataBits == 0) {
228      return "";
229    }
230    int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
231    int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
232    int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
233        : numberTriplets;
234    char encodedData[] = null;
235    encodedData = new char[numberQuartet * 4];
236    byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
237    int encodedIndex = 0;
238    int dataIndex = 0;
239    for (int i = 0; i < numberTriplets; i++) {
240      b1 = binaryData[dataIndex++];
241      b2 = binaryData[dataIndex++];
242      b3 = binaryData[dataIndex++];
243      l = (byte) (b2 & 0x0f);
244      k = (byte) (b1 & 0x03);
245      byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
246          : (byte) ((b1) >> 2 ^ 0xc0);
247      byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
248          : (byte) ((b2) >> 4 ^ 0xf0);
249      byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
250          : (byte) ((b3) >> 6 ^ 0xfc);
251      encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
252      encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
253      encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
254      encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
255    }
256    // form integral number of 6-bit groups
257    if (fewerThan24bits == EIGHTBIT) {
258      b1 = binaryData[dataIndex];
259      k = (byte) (b1 & 0x03);
260      byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
261          : (byte) ((b1) >> 2 ^ 0xc0);
262      encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
263      encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
264      encodedData[encodedIndex++] = PAD;
265      encodedData[encodedIndex++] = PAD;
266    } else if (fewerThan24bits == SIXTEENBIT) {
267      b1 = binaryData[dataIndex];
268      b2 = binaryData[dataIndex + 1];
269      l = (byte) (b2 & 0x0f);
270      k = (byte) (b1 & 0x03);
271      byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
272          : (byte) ((b1) >> 2 ^ 0xc0);
273      byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
274          : (byte) ((b2) >> 4 ^ 0xf0);
275      encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
276      encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
277      encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
278      encodedData[encodedIndex++] = PAD;
279    }
280    return new String(encodedData);
281  }
282  /**
283   * Decodes Base64 data into octects
284   *
285   * @param encoded
286   *            string containing Base64 data
287   * @return Array containind decoded data.
288   */
289  public static byte[] decode(String encoded) {
290    if (encoded == null) {
291      return null;
292    }
293    char[] base64Data = encoded.toCharArray();
294    // remove white spaces
295    int len = removeWhiteSpace(base64Data);
296    if (len % FOURBYTE != 0) {
297      return null;// should be divisible by four
298    }
299    int numberQuadruple = (len / FOURBYTE);
300    if (numberQuadruple == 0) {
301      return new byte[0];
302    }
303    byte decodedData[] = null;
304    byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
305    char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
306    int i = 0;
307    int encodedIndex = 0;
308    int dataIndex = 0;
309    decodedData = new byte[(numberQuadruple) * 3];
310    for (; i < numberQuadruple - 1; i++) {
311      if (!isData((d1 = base64Data[dataIndex++]))
312          || !isData((d2 = base64Data[dataIndex++]))
313          || !isData((d3 = base64Data[dataIndex++]))
314          || !isData((d4 = base64Data[dataIndex++]))) {
315        return null;
316      }// if found "no data" just return null
317      b1 = base64Alphabet[d1];
318      b2 = base64Alphabet[d2];
319      b3 = base64Alphabet[d3];
320      b4 = base64Alphabet[d4];
321      decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
322      decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
323      decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
324    }
325    if (!isData((d1 = base64Data[dataIndex++]))
326        || !isData((d2 = base64Data[dataIndex++]))) {
327      return null;// if found "no data" just return null
328    }
329    b1 = base64Alphabet[d1];
330    b2 = base64Alphabet[d2];
331    d3 = base64Data[dataIndex++];
332    d4 = base64Data[dataIndex++];
333    if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters
334      if (isPad(d3) && isPad(d4)) {
335        if ((b2 & 0xf) != 0)// last 4 bits should be zero
336        {
337          return null;
338        }
339        byte[] tmp = new byte[i * 3 + 1];
340        System.arraycopy(decodedData, 0, tmp, 0, i * 3);
341        tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
342        return tmp;
343      } else if (!isPad(d3) && isPad(d4)) {
344        b3 = base64Alphabet[d3];
345        if ((b3 & 0x3) != 0)// last 2 bits should be zero
346        {
347          return null;
348        }
349        byte[] tmp = new byte[i * 3 + 2];
350        System.arraycopy(decodedData, 0, tmp, 0, i * 3);
351        tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
352        tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
353        return tmp;
354      } else {
355        return null;
356      }
357    } else { // No PAD e.g 3cQl
358      b3 = base64Alphabet[d3];
359      b4 = base64Alphabet[d4];
360      decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
361      decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
362      decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
363    }
364    return decodedData;
365  }
366  /**
367   * remove WhiteSpace from MIME containing encoded Base64 data.
368   *
369   * @param data
370   *            the byte array of base64 data (with WS)
371   * @return the new length
372   */
373  private static int removeWhiteSpace(char[] data) {
374    if (data == null) {
375      return 0;
376    }
377    // count characters that's not whitespace
378    int newSize = 0;
379    int len = data.length;
380    for (int i = 0; i < len; i++) {
381      if (!isWhiteSpace(data[i])) {
382        data[newSize++] = data[i];
383      }
384    }
385    return newSize;
386  }
387}
388class PayResult {
389  private String resultStatus;
390  private String result;
391  private String memo;
392  public PayResult(String rawResult) {
393    if (TextUtils.isEmpty(rawResult))
394      return;
395    String[] resultParams = rawResult.split(";");
396    for (String resultParam : resultParams) {
397      if (resultParam.startsWith("resultStatus")) {
398        resultStatus = gatValue(resultParam, "resultStatus");
399      }
400      if (resultParam.startsWith("result")) {
401        result = gatValue(resultParam, "result");
402      }
403      if (resultParam.startsWith("memo")) {
404        memo = gatValue(resultParam, "memo");
405      }
406    }
407  }
408  @Override
409  public String toString() {
410    return "resultStatus={" + resultStatus + "};memo={" + memo
411        + "};result={" + result + "}";
412  }
413  private String gatValue(String content, String key) {
414    String prefix = key + "={";
415    return content.substring(content.indexOf(prefix) + prefix.length(),
416        content.lastIndexOf("}"));
417  }
418  /**
419   * @return the resultStatus
420   */
421  public String getResultStatus() {
422    return resultStatus;
423  }
424  /**
425   * @return the memo
426   */
427  public String getMemo() {
428    return memo;
429  }
430  /**
431   * @return the result
432   */
433  public String getResult() {
434    return result;
435  }
436}
437class SignUtils {
438  private static final String ALGORITHM = "RSA";
439  private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
440  private static final String DEFAULT_CHARSET = "UTF-8";
441  public static String sign(String content, String privateKey) {
442    try {
443      PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
444          Base64.decode(privateKey));
445      KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
446      PrivateKey priKey = keyf.generatePrivate(priPKCS8);
447      java.security.Signature signature = java.security.Signature
448          .getInstance(SIGN_ALGORITHMS);
449      signature.initSign(priKey);
450      signature.update(content.getBytes(DEFAULT_CHARSET));
451      byte[] signed = signature.sign();
452      return Base64.encode(signed);
453    } catch (Exception e) {
454      e.printStackTrace();
455    }
456    return null;
457  }
458}</span>

前面的几个常量是需要去支付宝官网获取的,获取后直接替换就ok,其他的代码基本都是从demo中copy出来的, 现在我们就将支付功能封装到了一个类中,那么如何使用呢?

1<span style="font-size: medium;">Alipay alipay = new Alipay(OrderConfirmActivity.this);
2alipay.setListener(mAlipayListener);
3alipay.pay(desc, mOrder.getShopName(), String.valueOf(orderAmount), orderSn, url);
4/**
5 * 支付宝支付回调
6 */
7private Alipay.OnAlipayListener mAlipayListener = new Alipay.OnAlipayListener() {
8  @Override
9  public void onSuccess() {
10    onOrderSubmitSuccess();
11  }
12  @Override
13  public void onCancel() {
14    onUserOrderCanceled();
15      Toast.makeText(OrderConfirmActivity.this, R.string.pay_failed,
16          Toast.LENGTH_SHORT).show();
17  }
18  @Override
19  public void onWait() {
20  }
21};</span>

new出对象来,只需要调用pay方法就ok啦, 不过支付的回调我们还是必须的,当然这个也不麻烦。这里说一下pay方法的几个参数,

  1. title 支付的标题
  2. desc 支付的描述
  3. price 支付的金额
  4. sn 商品的唯一货号
  5. url 服务器的回调url
这几个参数在做支付的时候服务器都会给到,但是要注意一下,这几个参数都不能为空或者空字符串,否则会支付失败
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值