Android app第三方支付宝支付接入教程

作者:峰子_it 时间:2022-06-05 20:02:19 

支付宝的接入相对比较简单,看看支付宝官网的文档基本都能搞定,但是切记一点让你们的后台也要搞清楚支付宝的流程,重中之重。

1、注意事项
开发前一定要阅读支付宝官方文档
强烈建议签名等处理在后台处理,我这个是测试是在自己本地写的,不要吐槽
想获取支付宝合作商户ID,及支付宝公钥请点击支付宝链接,生成密钥及PKCS8转码工具在文档中
添加Android.permission.INTERNET权限和android.permission.ACCESS_NETWORK_STATE权限
要导入支付宝的包
2、特别注意事项(坑点)
下载支付宝的官网之后生成你所需要的密钥及PKCS8转码一定要小心

代码:
MainActivity中调起支付:Pay pay = new Pay(AffirmOrderActivity.this, paymoney);

Pay 类


public class Pay {

/**以下四项这些数值机密填入自己申请的就好**/
 // 商户PID
 public static final String PARTNER = "";
 // 商户收款账号
 public static final String SELLER = "";
 // 商户私钥,pkcs8格式
 public static final String RSA_PRIVATE = "";
 // 支付宝公钥
 public static final String RSA_PUBLIC = "";

private Activity context;
 private String mgoods,mprice,micon;
 private int mtype;
 private String mOutTradeNo;
 public Pay(Activity activity, String goods,String goodsmore,String price,String icon,int type, String outTradeNo) {
   context = activity;
   mprice = price;
   pay(price);
 }

private Handler mHandler = new Handler() {

public void handleMessage(Message msg) {
     switch (msg.what) {
       case SDK_PAY_FLAG: {
         PayResult payResult = new PayResult((String) msg.obj);
         /**
          * 同步返回的结果必须放置到服务端进行验证(验证的规则请看https://doc.open.alipay.com/doc2/
          * detail.htm?spm=0.0.0.0.xdvAU6&treeId=59&articleId=103665&
          * docType=1) 建议商户依赖异步通知
          */
         String resultInfo = payResult.getResult();// 同步返回需要验证的信息

String resultStatus = payResult.getResultStatus();
         // 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档
         if (TextUtils.equals(resultStatus, "9000")) {
           Toast.makeText(context, "支付成功", Toast.LENGTH_SHORT).show();

} else {
           // 判断resultStatus 为非"9000"则代表可能支付失败
           // "8000"代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)
           if (TextUtils.equals(resultStatus, "8000")) {
             Toast.makeText(context, "支付结果确认中", Toast.LENGTH_SHORT).show();

} else {
             // 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误
             Toast.makeText(context, "支付失败", Toast.LENGTH_SHORT).show();

}
         }
         break;
       }
       default:
         break;
     }
   };
 };

/**
  * call alipay sdk pay. 调用SDK支付
  *
  */
 public void pay(String goods,String goodsmore,String price) {
   if (TextUtils.isEmpty(PARTNER) || TextUtils.isEmpty(RSA_PRIVATE) || TextUtils.isEmpty(SELLER)) {
     new AlertDialog.Builder(context).setTitle("警告").setMessage("需要配置PARTNER | RSA_PRIVATE| SELLER")
         .setPositiveButton("确定", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialoginterface, int i) {
             //
//              finish();
           }
         }).show();
     return;
   }
   String orderInfo = getOrderInfo(goods, goodsmore, price);

String sign = sign(orderInfo);

try {
     /**
      * 仅需对sign 做URL编码
      */
     sign = URLEncoder.encode(sign, "UTF-8");

} catch (UnsupportedEncodingException e) {
     e.printStackTrace();
   }

/**
    * 完整的符合支付宝参数规范的订单信息
    */
   final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();
   Log.i("lff", "orderInfo == " +orderInfo);
   Log.i("lff", "sign == " +sign);    Runnable payRunnable = new Runnable() {

@Override
     public void run() {
       // 构造PayTask 对象
       PayTask alipay = new PayTask(context);
       // 调用支付接口,获取支付结果
       String result = alipay.pay(payInfo, true);

Message msg = new Message();
       msg.what = SDK_PAY_FLAG;
       msg.obj = result;
       mHandler.sendMessage(msg);
     }
   };

// 必须异步调用
   Thread payThread = new Thread(payRunnable);
   payThread.start();
 }

/**
  * get the sdk version. 获取SDK版本号
  *
  */
 public void getSDKVersion() {
   PayTask payTask = new PayTask(context);
   String version = payTask.getVersion();
   Toast.makeText(context, version, Toast.LENGTH_SHORT).show();
 }

/**
  * create the order info. 创建订单信息
  *
  */
 private String getOrderInfo(String subject, String body, String price) {

// 签约合作者身份ID
   String orderInfo = "partner=" + "\"" + PARTNER + "\"";

// 签约卖家支付宝账号
   orderInfo += "&seller_id=" + "\"" + SELLER + "\"";

// 商户网站唯一订单号
   orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";

// 商品名称
   orderInfo += "&subject=" + "\"" + subject + "\"";

// 商品详情
   orderInfo += "&body=" + "\"" + body + "\"";

// 商品金额
   orderInfo += "&total_fee=" + "\"" + "0.01" + "\"";

// 服务器异步通知页面路径
//    orderInfo += "&notify_url=" + "\"" + "http://notify.msp.hk/notify.htm" + "\"";
   orderInfo += "&notify_url=" + "\"" + "http://112.74.129.252/new/zfbCallback" + "\"";
   // 服务接口名称, 固定值
   orderInfo += "&service=\"mobile.securitypay.pay\"";

// 支付类型, 固定值
   orderInfo += "&payment_type=\"1\"";

// 参数编码, 固定值
   orderInfo += "&_input_charset=\"utf-8\"";

// 设置未付款交易的超时时间
   // 默认30分钟,一旦超时,该笔交易就会自动被关闭。
   // 取值范围:1m~15d。
   // m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
   // 该参数数值不接受小数点,如1.5h,可转换为90m。
   orderInfo += "&it_b_pay=\"30m\"";

// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
   // orderInfo += "&extern_token=" + "\"" + extern_token + "\"";

// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
   orderInfo += "&return_url=\"m.alipay.com\"";

// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
   // orderInfo += "&paymethod=\"expressGateway\"";
   return orderInfo;
 }

/**
  * get the out_trade_no for an order. 生成商户订单号,该值在商户端应保持唯一(可自定义格式规范)
  *
  */
 private 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;
   return mOutTradeNo;
 }

/**
  * sign the order info. 对订单信息进行签名
  *
  * @param content
  *      待签名订单信息
  */
 private String sign(String content) {
   return SignUtils.sign(content, RSA_PRIVATE);
 }

/**
  * get the sign type we use. 获取签名方式
  *
  */
 private String getSignType() {
   return "sign_type=\"RSA\"";
 }

}

其它的工具类,原封不动拷贝过去就好

Base64 类


package com.easyhomework.teacher.ui;

public final class Base64 {

private static final int BASELENGTH = 128;
 private static final int LOOKUPLENGTH = 64;
 private static final int TWENTYFOURBITGROUP = 24;
 private static final int EIGHTBIT = 8;
 private static final int SIXTEENBIT = 16;
 private static final int FOURBYTE = 4;
 private static final int SIGN = -128;
 private static char PAD = '=';
 private static byte[] base64Alphabet = new byte[BASELENGTH];
 private static char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];

static {
   for (int i = 0; i < BASELENGTH; ++i) {
     base64Alphabet[i] = -1;
   }
   for (int i = 'Z'; i >= 'A'; i--) {
     base64Alphabet[i] = (byte) (i - 'A');
   }
   for (int i = 'z'; i >= 'a'; i--) {
     base64Alphabet[i] = (byte) (i - 'a' + 26);
   }

for (int i = '9'; i >= '0'; i--) {
     base64Alphabet[i] = (byte) (i - '0' + 52);
   }

base64Alphabet['+'] = 62;
   base64Alphabet['/'] = 63;

for (int i = 0; i <= 25; i++) {
     lookUpBase64Alphabet[i] = (char) ('A' + i);
   }

for (int i = 26, j = 0; i <= 51; i++, j++) {
     lookUpBase64Alphabet[i] = (char) ('a' + j);
   }

for (int i = 52, j = 0; i <= 61; i++, j++) {
     lookUpBase64Alphabet[i] = (char) ('0' + j);
   }
   lookUpBase64Alphabet[62] = (char) '+';
   lookUpBase64Alphabet[63] = (char) '/';

}

private static boolean isWhiteSpace(char octect) {
   return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
 }

private static boolean isPad(char octect) {
   return (octect == PAD);
 }

private static boolean isData(char octect) {
   return (octect < BASELENGTH && base64Alphabet[octect] != -1);
 }

/**
  * Encodes hex octects into Base64
  *
  * @param binaryData
  *      Array containing binaryData
  * @return Encoded Base64 array
  */
 public static String encode(byte[] binaryData) {

if (binaryData == null) {
     return null;
   }

int lengthDataBits = binaryData.length * EIGHTBIT;
   if (lengthDataBits == 0) {
     return "";
   }

int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
   int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
   int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
       : numberTriplets;
   char encodedData[] = null;

encodedData = new char[numberQuartet * 4];

byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;

int encodedIndex = 0;
   int dataIndex = 0;

for (int i = 0; i < numberTriplets; i++) {
     b1 = binaryData[dataIndex++];
     b2 = binaryData[dataIndex++];
     b3 = binaryData[dataIndex++];

l = (byte) (b2 & 0x0f);
     k = (byte) (b1 & 0x03);

byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
         : (byte) ((b1) >> 2 ^ 0xc0);
     byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
         : (byte) ((b2) >> 4 ^ 0xf0);
     byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
         : (byte) ((b3) >> 6 ^ 0xfc);

encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
     encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
     encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
     encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
   }

// form integral number of 6-bit groups
   if (fewerThan24bits == EIGHTBIT) {
     b1 = binaryData[dataIndex];
     k = (byte) (b1 & 0x03);

byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
         : (byte) ((b1) >> 2 ^ 0xc0);
     encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
     encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
     encodedData[encodedIndex++] = PAD;
     encodedData[encodedIndex++] = PAD;
   } else if (fewerThan24bits == SIXTEENBIT) {
     b1 = binaryData[dataIndex];
     b2 = binaryData[dataIndex + 1];
     l = (byte) (b2 & 0x0f);
     k = (byte) (b1 & 0x03);

byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
         : (byte) ((b1) >> 2 ^ 0xc0);
     byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
         : (byte) ((b2) >> 4 ^ 0xf0);

encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
     encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
     encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
     encodedData[encodedIndex++] = PAD;
   }

return new String(encodedData);
 }

/**
  * Decodes Base64 data into octects
  *
  * @param encoded
  *      string containing Base64 data
  * @return Array containind decoded data.
  */
 public static byte[] decode(String encoded) {

if (encoded == null) {
     return null;
   }

char[] base64Data = encoded.toCharArray();
   // remove white spaces
   int len = removeWhiteSpace(base64Data);

if (len % FOURBYTE != 0) {
     return null;// should be divisible by four
   }

int numberQuadruple = (len / FOURBYTE);

if (numberQuadruple == 0) {
     return new byte[0];
   }

byte decodedData[] = null;
   byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
   char d1 = 0, d2 = 0, d3 = 0, d4 = 0;

int i = 0;
   int encodedIndex = 0;
   int dataIndex = 0;
   decodedData = new byte[(numberQuadruple) * 3];

for (; i < numberQuadruple - 1; i++) {

if (!isData((d1 = base64Data[dataIndex++]))
         || !isData((d2 = base64Data[dataIndex++]))
         || !isData((d3 = base64Data[dataIndex++]))
         || !isData((d4 = base64Data[dataIndex++]))) {
       return null;
     }// if found "no data" just return null

b1 = base64Alphabet[d1];
     b2 = base64Alphabet[d2];
     b3 = base64Alphabet[d3];
     b4 = base64Alphabet[d4];

decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
     decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
     decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
   }

if (!isData((d1 = base64Data[dataIndex++]))
       || !isData((d2 = base64Data[dataIndex++]))) {
     return null;// if found "no data" just return null
   }

b1 = base64Alphabet[d1];
   b2 = base64Alphabet[d2];

d3 = base64Data[dataIndex++];
   d4 = base64Data[dataIndex++];
   if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters
     if (isPad(d3) && isPad(d4)) {
       if ((b2 & 0xf) != 0)// last 4 bits should be zero
       {
         return null;
       }
       byte[] tmp = new byte[i * 3 + 1];
       System.arraycopy(decodedData, 0, tmp, 0, i * 3);
       tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
       return tmp;
     } else if (!isPad(d3) && isPad(d4)) {
       b3 = base64Alphabet[d3];
       if ((b3 & 0x3) != 0)// last 2 bits should be zero
       {
         return null;
       }
       byte[] tmp = new byte[i * 3 + 2];
       System.arraycopy(decodedData, 0, tmp, 0, i * 3);
       tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
       tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
       return tmp;
     } else {
       return null;
     }
   } else { // No PAD e.g 3cQl
     b3 = base64Alphabet[d3];
     b4 = base64Alphabet[d4];
     decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
     decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
     decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);

}

return decodedData;
 }

/**
  * remove WhiteSpace from MIME containing encoded Base64 data.
  *
  * @param data
  *      the byte array of base64 data (with WS)
  * @return the new length
  */
 private static int removeWhiteSpace(char[] data) {
   if (data == null) {
     return 0;
   }

// count characters that's not whitespace
   int newSize = 0;
   int len = data.length;
   for (int i = 0; i < len; i++) {
     if (!isWhiteSpace(data[i])) {
       data[newSize++] = data[i];
     }
   }
   return newSize;
 }
}

总结一下支付宝支付步骤:1、生成秘钥私钥等(一般是后台处理的) ;2、支付宝包复制带项目中 ;3、调用支付(上述MainActivity和pay类) 4、添加工具类

标签:Android,app,支付宝
0
投稿

猜你喜欢

  • ref与out之间的区别深入解析

    2023-08-05 23:45:28
  • Android 动画之TranslateAnimation应用详解

    2023-06-27 06:17:59
  • Android编程简单设置ListView分割线的方法

    2021-07-21 20:24:33
  • Java实现世界上最快的排序算法Timsort的示例代码

    2021-12-14 17:57:27
  • 深入理解Java并发编程之ThreadLocal

    2023-11-21 02:43:42
  • Android 应用启动欢迎界面广告的实现实例

    2023-01-26 07:34:11
  • Java代码优化细节

    2023-06-26 09:34:34
  • C#对Xamarin框架进行数据绑定

    2022-04-07 23:36:50
  • java中addMouseListener()方法的使用

    2021-07-07 19:29:35
  • java图的深度优先遍历实现随机生成迷宫

    2023-06-26 06:06:05
  • Java模拟多线程实现抢票代码实例

    2022-11-17 07:41:51
  • 基于Silverlight DataGrid中无代码设置开始与结束日期DatePicker的实现方法

    2023-05-04 16:34:50
  • AndroidStudio4.0 New Class的坑(小结)

    2022-07-29 15:06:48
  • C# 迭代器分部类与索引器详情

    2023-10-16 21:18:18
  • kafka监听问题的解决和剖析

    2021-06-28 04:41:25
  • C#算法之散列表

    2022-07-30 19:05:52
  • JNI语言基本知识

    2022-01-20 20:02:46
  • 详解Android的两种事件处理机制

    2023-10-05 23:37:20
  • Ubuntu中为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序

    2022-07-20 15:09:51
  • Java实现快速排序过程分析

    2023-07-27 18:40:57
  • asp之家 软件编程 m.aspxhome.com