一、前言
最近做的項目剛好要內建支付寶,上網找了很多資料,介紹得感覺不是很全面,是以我經過這兩天的內建,順便記錄下來,學習交流。需要的朋友也可以看看。主要內建還是參照了官方給出的demo,再參照demo進行封裝,現在使用起來變得友善好多。而且文章裡面還提到了內建過程中遇到的一些問題,當然最後也都解決了。
二、準備工作
支付寶開放平台上面也明确了,目前僅僅支援企業使用者申請,是以個人開發者就沒法使用到。希望支付寶早日可以開放給個人開發者。
支付寶的內建是相對比較麻煩,其中涉及到了很多東西要弄,要生成私鑰公鑰等等。文檔裡面也有詳細說到如何如何生成那些東西,不過就是文檔的内容量有點多了,看起來總抓不住前後,這裡我稍作整理,把android需要用到的提取出來了。
1、PID
首先說一下就是支付寶的支付是這樣的,企業使用者申請了支付寶之後,支付寶就會提供一個合作者id,就是所謂的pid,是2088開頭的16位純數字;
2、支付寶賬戶
這個就是你用于收款用的支付寶賬号,要跟申請時候同一個。
以下幾個要運作我附件中的“移動支付接口智能SDK版"中,\openssl\bin檔案夾下面的openssl.exe生成,這個是由支付寶提供的
3、RSA私鑰:genrsa -out rsa_private_key.pem 1024
運作完指令行可以看到bin檔案夾下面會生成私鑰
4、RSA公鑰:rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
運作完指令行後可以看到生成了公鑰
5、PKCS8編碼的私鑰:pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
運作完後,将生成的東西拷貝下來放到文本檔案裡面就行。這後面要用到的!!包括begin跟end那兩句一起存起來
三、支付過程
需要進行再封裝的主要有下面這個類,做幾點說明,AliPayParamsBO是我封裝的一個實體類,因為我把剛剛上面講到的那些PID、私鑰啊等等都放在服務端了,這樣會比較安全,就算别人反編譯了你的項目,那也看不到什麼東西,支付寶官方也是這樣建議的。測試的時候,可以把這個AliPayParamsBO類,裝進你生成的那些參數去測試就好啦,至于OrderBO類,也是我封裝的一個類,裡面主要包含的是這個訂單相關的一些東西,比如商品名稱、商品介紹,價格等等,這些在支付過程中都是必要的。
而需要強調一點就是,産生這個支付過程中,我先是構造好需要請求的參數,注意一點就是我在createOrderInfo()方法中對參數進行構造,但是 sign、sign_type 兩個參數先不要參與,因為這兩個參數不需要參與簽名,等前面那些參數構造好了之後,簽完名再将sign、sign_type 兩個參數構造進去,再進行支付。
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import android.os.Handler;
import android.os.Message;
import com.alipay.android.app.sdk.AliPay;
import com.common.ui.BaseActivity;
import com.common.utils.CLog;
import com.onecity.cs.bo.AliPayParamsBO;
import com.onecity.cs.bo.OrderBO;
/**
* @author 林楷鵬
* @description 支付寶相關操作
* @create 2014-11-1下午12:11:20
*
*/
public class AlipayUtil {
private static final String TAG = "PayActivity";
public static final int RQF_PAY = 1;
public static final int RQF_LOGIN = 2;
public static void pay(final BaseActivity activity, AliPayParamsBO aliPayBO, OrderBO orderBO, final Handler handler){
try {
String info = createOrderInfo(orderBO, aliPayBO);
String sign = Rsa.sign(info, aliPayBO.getPrivate_key_pkcs8());
sign = URLEncoder.encode(sign, "utf-8");
info += "&sign=\"" + sign + "\"&" + getSignType();
CLog.log("ExternalPartner", "start pay");
// start the pay.
CLog.log(TAG, "info = " + info);
final String orderInfo = info;
new Thread() {
public void run() {
AliPay alipay = new AliPay(activity, handler);
//設定為沙箱模式,不設定預設為線上環境
//alipay.setSandBox(true);
String result = alipay.pay(orderInfo);
CLog.log(TAG, "result = " + result);
Message msg = handler.obtainMessage();
msg.what = RQF_PAY;
msg.obj = result;
handler.sendMessage(msg);
}
}.start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 封裝訂單資訊
* @param orderBO
* @return
* @throws UnsupportedEncodingException
*/
private static String createOrderInfo(OrderBO orderBO, AliPayParamsBO aliPayBO)
throws UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
sb.append("partner=\"");
sb.append(aliPayBO.getPid());
sb.append("\"&out_trade_no=\"");
sb.append(orderBO.getOrder_sn());
sb.append("\"&subject=\"");
sb.append(orderBO.getSubject());
sb.append("\"&body=\"");
sb.append(orderBO.getBody());
sb.append("\"&total_fee=\"");
sb.append(/*orderBO.getAmount()*/"0.01");
sb.append("\"¬ify_url=\"");
// 網址需要做URL編碼
sb.append(URLEncoder.encode(aliPayBO.getNotify_url(), "utf-8"));
sb.append("\"&service=\"mobile.securitypay.pay");
sb.append("\"&_input_charset=\"UTF-8");
sb.append("\"&return_url=\"");
sb.append(URLEncoder.encode("http://m.alipay.com", "utf-8"));
sb.append("\"&payment_type=\"1");
sb.append("\"&seller_id=\"");
sb.append(aliPayBO.getAccount());
// 如果show_url值為空,可不傳
// sb.append("\"&show_url=\"");
sb.append("\"&it_b_pay=\"1m");
sb.append("\"");
return new String(sb);
}
/**
* 擷取sign_type參數資訊,因為該參數不需要參加簽名
* @return
*/
private static String getSignType() {
return "sign_type=\"RSA\"";
}
}
遇到的問題:整個過程還是比較順利的,一開始我是使用了4.0系統的手機進行測試,也能夠正常使用。但是跑給同僚手機之後,問題出現了,居然出現了。。點選支付的時候始終喚不起支付頁面,還報了 failure calling remote service 異常,然後就挺納悶,查了代碼發現好像沒啥問題。
馬上去列印log,看到了如下問題:
看了以上異常資訊之後我的第一反應就是難道我的私鑰弄錯了,但想想4.0還是沒問題的啊。後來就追查到了代碼中,就在Rsa類中的sign方法,這是支付寶給出的類,我就在異常中将異常資訊列印出來,果真
還是編碼問題。
public static String sign(String content, String privateKey) {
String charset = "UTF-8";
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
Base64.decode(privateKey));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature
.getInstance(SIGN_ALGORITHMS);
signature.initSign(priKey);
signature.update(content.getBytes(charset));
byte[] signed = signature.sign();
return Base64.encode(signed);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Exception="+e.getMessage());
}
return null;
}
然後我就突然想到了上面生成的 “PKCS8編碼的私鑰”,然後将剛剛上面那個AlipayUtil類的pay方法裡面的
String sign = Rsa.sign(info, aliPayBO.getPrivate_key_pkcs8());
簽名時用的就是 “ PKCS8編碼的私鑰”(原本出問題是用到RSA私鑰),代碼中改過來了。這次就行了啦,無論4.0以下還是以上通殺。界面如下:
好啦,用戶端的內建大概就是這樣,其他相關的類是按照支付寶demo裡面的,就不要展示出來了,需要的到 代碼下載下傳裡面去下載下傳就ok啦~