天天看點

android 支付寶SDK內建

一、前言

最近做的項目剛好要內建支付寶,上網找了很多資料,介紹得感覺不是很全面,是以我經過這兩天的內建,順便記錄下來,學習交流。需要的朋友也可以看看。主要內建還是參照了官方給出的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檔案夾下面會生成私鑰

android 支付寶SDK內建

4、RSA公鑰:rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

運作完指令行後可以看到生成了公鑰

android 支付寶SDK內建

5、PKCS8編碼的私鑰:pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt

運作完後,将生成的東西拷貝下來放到文本檔案裡面就行。這後面要用到的!!包括begin跟end那兩句一起存起來

android 支付寶SDK內建

三、支付過程

需要進行再封裝的主要有下面這個類,做幾點說明,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,看到了如下問題:

android 支付寶SDK內建
android 支付寶SDK內建

看了以上異常資訊之後我的第一反應就是難道我的私鑰弄錯了,但想想4.0還是沒問題的啊。後來就追查到了代碼中,就在Rsa類中的sign方法,這是支付寶給出的類,我就在異常中将異常資訊列印出來,果真

android 支付寶SDK內建

還是編碼問題。

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以下還是以上通殺。界面如下:

android 支付寶SDK內建

好啦,用戶端的內建大概就是這樣,其他相關的類是按照支付寶demo裡面的,就不要展示出來了,需要的到 代碼下載下傳裡面去下載下傳就ok啦~

繼續閱讀