支付寶的接入相對比較簡單,看看支付寶官網的文檔基本都能搞定,但是切記一點讓你們的背景也要搞清楚支付寶的流程,不然對接起來是一件很蛋疼的事情。
開始搬磚
注意事項
開發前一定要閱讀支付寶官方文檔
強烈建議簽名等處理在背景處理,我這個是測試是在自己本地寫的,不要吐槽
想擷取支付寶合作商戶ID,及支付寶公鑰請點選支付寶連結,生成密鑰及PKCS8轉碼工具在文檔中
添加android.permission.INTERNET權限和android.permission.ACCESS_NETWORK_STATE權限
要導入支付寶的包
特别注意事項(坑點)
下載下傳支付寶的官網之後生成你所需要的密鑰及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 += "¬ify_url=" + "\"" + "http://notify.msp.hk/notify.htm" + "\"";
orderInfo += "¬ify_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 = ;
private static final int LOOKUPLENGTH = ;
private static final int TWENTYFOURBITGROUP = ;
private static final int EIGHTBIT = ;
private static final int SIXTEENBIT = ;
private static final int FOURBYTE = ;
private static final int SIGN = -;
private static char PAD = '=';
private static byte[] base64Alphabet = new byte[BASELENGTH];
private static char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
static {
for (int i = ; i < BASELENGTH; ++i) {
base64Alphabet[i] = -;
}
for (int i = 'Z'; i >= 'A'; i--) {
base64Alphabet[i] = (byte) (i - 'A');
}
for (int i = 'z'; i >= 'a'; i--) {
base64Alphabet[i] = (byte) (i - 'a' + );
}
for (int i = '9'; i >= '0'; i--) {
base64Alphabet[i] = (byte) (i - '0' + );
}
base64Alphabet['+'] = ;
base64Alphabet['/'] = ;
for (int i = ; i <= ; i++) {
lookUpBase64Alphabet[i] = (char) ('A' + i);
}
for (int i = , j = ; i <= ; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('a' + j);
}
for (int i = , j = ; i <= ; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('0' + j);
}
lookUpBase64Alphabet[] = (char) '+';
lookUpBase64Alphabet[] = (char) '/';
}
private static boolean isWhiteSpace(char octect) {
return (octect == || octect == || octect == || octect == );
}
private static boolean isPad(char octect) {
return (octect == PAD);
}
private static boolean isData(char octect) {
return (octect < BASELENGTH && base64Alphabet[octect] != -);
}
/**
* 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 == ) {
return "";
}
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
int numberQuartet = fewerThan24bits != ? numberTriplets +
: numberTriplets;
char encodedData[] = null;
encodedData = new char[numberQuartet * ];
byte k = , l = , b1 = , b2 = , b3 = ;
int encodedIndex = ;
int dataIndex = ;
for (int i = ; i < numberTriplets; i++) {
b1 = binaryData[dataIndex++];
b2 = binaryData[dataIndex++];
b3 = binaryData[dataIndex++];
l = (byte) (b2 & );
k = (byte) (b1 & );
byte val1 = ((b1 & SIGN) == ) ? (byte) (b1 >> )
: (byte) ((b1) >> ^ );
byte val2 = ((b2 & SIGN) == ) ? (byte) (b2 >> )
: (byte) ((b2) >> ^ );
byte val3 = ((b3 & SIGN) == ) ? (byte) (b3 >> )
: (byte) ((b3) >> ^ );
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << )];
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << ) | val3];
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & ];
}
// form integral number of 6-bit groups
if (fewerThan24bits == EIGHTBIT) {
b1 = binaryData[dataIndex];
k = (byte) (b1 & );
byte val1 = ((b1 & SIGN) == ) ? (byte) (b1 >> )
: (byte) ((b1) >> ^ );
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << ];
encodedData[encodedIndex++] = PAD;
encodedData[encodedIndex++] = PAD;
} else if (fewerThan24bits == SIXTEENBIT) {
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + ];
l = (byte) (b2 & );
k = (byte) (b1 & );
byte val1 = ((b1 & SIGN) == ) ? (byte) (b1 >> )
: (byte) ((b1) >> ^ );
byte val2 = ((b2 & SIGN) == ) ? (byte) (b2 >> )
: (byte) ((b2) >> ^ );
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << )];
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << ];
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 != ) {
return null;// should be divisible by four
}
int numberQuadruple = (len / FOURBYTE);
if (numberQuadruple == ) {
return new byte[];
}
byte decodedData[] = null;
byte b1 = , b2 = , b3 = , b4 = ;
char d1 = , d2 = , d3 = , d4 = ;
int i = ;
int encodedIndex = ;
int dataIndex = ;
decodedData = new byte[(numberQuadruple) * ];
for (; i < numberQuadruple - ; 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 << | b2 >> );
decodedData[encodedIndex++] = (byte) (((b2 & ) << ) | ((b3 >> ) & ));
decodedData[encodedIndex++] = (byte) (b3 << | 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 & ) != )// last 4 bits should be zero
{
return null;
}
byte[] tmp = new byte[i * + ];
System.arraycopy(decodedData, , tmp, , i * );
tmp[encodedIndex] = (byte) (b1 << | b2 >> );
return tmp;
} else if (!isPad(d3) && isPad(d4)) {
b3 = base64Alphabet[d3];
if ((b3 & ) != )// last 2 bits should be zero
{
return null;
}
byte[] tmp = new byte[i * + ];
System.arraycopy(decodedData, , tmp, , i * );
tmp[encodedIndex++] = (byte) (b1 << | b2 >> );
tmp[encodedIndex] = (byte) (((b2 & ) << ) | ((b3 >> ) & ));
return tmp;
} else {
return null;
}
} else { // No PAD e.g 3cQl
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << | b2 >> );
decodedData[encodedIndex++] = (byte) (((b2 & ) << ) | ((b3 >> ) & ));
decodedData[encodedIndex++] = (byte) (b3 << | 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 ;
}
// count characters that's not whitespace
int newSize = ;
int len = data.length;
for (int i = ; i < len; i++) {
if (!isWhiteSpace(data[i])) {
data[newSize++] = data[i];
}
}
return newSize;
}
}
總結一下
支付寶支付一共五部
生成秘鑰私鑰等(一般是背景處理的)
支付寶包複制帶項目中
調用支付(上述MainActivity和pay類)
添加工具類
歡迎入群一起學習 QQ群 548629089