Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發筆記(一百零六)支付繳費SDK

Android開發筆記(一百零六)支付繳費SDK

編輯:關於Android編程

第三方支付

第三方支付指的是第三方平台與各銀行簽約,在買方與賣方之間實現中介擔保,從而增強了支付交易的安全性。國內常用的支付平台主要是支付寶和微信支付,其中支付寶的市場份額為71.5%,微信支付的市場份額為15.99%,也就是說這兩家壟斷了八分之七的支付市場(2015年數據)。除此之外,還有幾個app開發會用到的支付平台,包括:銀聯支付,主要用於公共事業繳費,如水電煤、有線電視、移動電信等等的充值;易寶支付,主要用於各種報名考試的繳費,特別是公務員與事業單位招考;快錢,被萬達收購,主要用於航空旅行、教育培訓、游戲娛樂等網站的支付;京東支付,主要用於京東商城的支付;百度錢包,主要用於百度系的電商平台。


因為第三方支付只是個中介,交易流程要多次確認,所以app若要集成支付sdk,得進行以下處理:
1、除了作為買方的用戶自己擁有支付賬號,開發者還得申請作為賣方的商戶賬號。
2、支付過程中,雖然允許app直接與第三方支付平台通信,但是最好app要有自己的後台服務器,由自己的後台與第三方平台進行通信。這樣做的好處是,一方面自己後台掌握了用戶交易記錄,做賬有依據,管理也方便;另一方面,關鍵交易在自己後台處理,也減少了惡意篡改的風險。
3、為保證信息安全,需對關鍵數據進行加密處理,如支付寶采用RSA+BASE64算法,微信支付采用MD5算法,銀聯支付采用RSA算法。有關數據加密算法的說明參見《Android開發筆記(七十二)數據加密算法》。


支付寶支付

交易流程

支付寶支付的交易流程大致如下:
1、按照指定格式封裝好交易信息;
2、對交易信息進行RSA加密與URL編碼;
3、調用支付接口,傳入加密好的信息串;(這步要另開線程處理,不能放在UI線程中)
4、支付寶sdk在界面下方彈出支付窗口,用戶輸入支付帳號信息,提交支付;
5、收到支付完成的結果,判斷支付狀態是成功還是失敗;


集成步驟

支付寶sdk的集成比較簡單,除了必要的權限外,無需再修改AndroidManifest.xml,jar包也只要導入alipaySdk-20160516.jar。


代碼方面,支付寶官方給的demo采用了Thread+Handler的異步處理模式,不過該模式要把代碼寫在Activity中,不便管理和維護,因此我的測試代碼將它改造為Android自帶的異步任務處理即AsyncTask方式。


測試帳號

支付寶官方demo沒有給出測試的商戶賬號,下面是我在網上找到的測試帳號:
	// 商戶PID
	public static final String PARTNER = "2088811977704990";
	// 商戶收款賬號
	public static final String SELLER = "[email protected]";
	// 商戶私鑰,pkcs8格式
	public static final String RSA_PRIVATE = 
		                "MIICXQIBAAKBgQDlQ468L1A7Q+GG80/Z8f3IsSiiFIluSxfTTSuJ/XSPzvYS+bMZ" 
		               +"AQLMqq/nGhkp+1Q5pHF9LAQtQS3gL2pqzbKdtvZSsy/tNFFQcGCsgK2ygMl+MW/F"
		               +"g/ufx7c1jy1kZAeDyl1m302dnRrtSgDalkgH7FKRcmDxbXPTnFGHbg9zMQIDAQAB"
		               +"AoGAa28wGQF28H7L1Yh5V+FtkrlqGCHVkQjBfnRAPea205kheRzoD4SIwk4OJhb1"
		               +"ydWLz4M+53BT+Lz9eXveu3PvCdQe9zMIVC5dKUNVYCvvcHZ+Ot8HriiuwGPb3Quu"
		               +"twbnLGM5gxxPDo0yUyWrfaVn/qR35mS6TDfmgowVG8CmBpECQQDzuhodR/Jgxrtn"
		               +"tka+88alyy+BfjUZqNloPuE7JfXrpOxH5lodk7Y4lTki/dlo5BrK+hrismLFr9Du"
		               +"ueAJ7G9dAkEA8M8C6VnpUMAK5+rYcjKnQssDqcMfurKYEil1BD/TUdSbLI6v8p02"
		               +"mv1ApuTVtQQypZJKIFfurGk0g0QlvzLZ5QJAGfY38+iHDAH/UnPbI1oKTfzPyaZs"
		               +"95fB2NXh3hAUGw7NUHdcIAxs+6gBlxWdRAwQQpDTrlQ8KzyoL9XC5Ku3zQJBALO8"
		               +"j5vEtFTFQl6f9zYlgJpmFTHcpg4fx0mnD+RAD2aAneHADquzlFJSvLLVEn2tyG+0"
		               +"pQdHGqotTDi94L65IdECQQDb1h+5kugCu47IxsDkrLRsKVcr8dSDMORyeT1L0HWR"
		               +"ctramBu+2PBz2UKC6+9dQ+ZQH4XTKpBSvkyZH4mYi1de";
//	// 支付寶公鑰
//	public static final String RSA_PUBLIC = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRAFljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQEB/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5KsiNG9zpgmLCUYuLkxpLQIDAQAB";


下面是支付寶支付的效果截圖
\


下面是支付寶支付的示例代碼
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Random;

import com.alipay.sdk.app.PayTask;
import com.example.exmpay.alipay.bean.AlipayConstants;
import com.example.exmpay.alipay.bean.PayResult;
import com.example.exmpay.alipay.util.SignUtils;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.widget.Toast;

public class AlipayTask extends AsyncTask {

	private static final String TAG = "AlipayTask";
	private Context context;
	private ProgressDialog dialog;
	
	public AlipayTask(Context context) {
		this.context = context;
	}
	
	@Override
	protected void onPreExecute() {
		if (TextUtils.isEmpty(AlipayConstants.PARTNER) 
				|| TextUtils.isEmpty(AlipayConstants.RSA_PRIVATE) 
				|| TextUtils.isEmpty(AlipayConstants.SELLER)) {
			new AlertDialog.Builder(context).setTitle("警告").setMessage("需要配置PARTNER | RSA_PRIVATE| SELLER")
					.setPositiveButton("確定", new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialoginterface, int i) {
						}
					}).show();
			cancel(true);
		} else {
			dialog = ProgressDialog.show(context, "提示", "正在啟動支付寶...");
		}
	}

	@Override
	protected String doInBackground(Void... params) {
		String orderInfo = getOrderInfo("測試的商品", "該測試商品的詳細描述", "0.01");

		//特別注意,這裡的簽名邏輯需要放在服務端,切勿將私鑰洩露在代碼中!
		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();
		// 構造PayTask 對象
		PayTask alipay = new PayTask((Activity) context);
		// 調用支付接口,獲取支付結果
		String result = alipay.pay(payInfo, false);
		return result;
	}

	@Override
	protected void onPostExecute(String result) {
		if (dialog != null) {
			dialog.dismiss();
		}

		PayResult payResult = new PayResult(result);

		// 支付寶返回此次支付結果及加簽,建議對支付寶簽名信息拿簽約時支付寶提供的公鑰做驗簽
		String resultInfo = payResult.getResult();
		Toast.makeText(context, "resultInfo="+resultInfo, Toast.LENGTH_SHORT).show();

		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, "支付寶繳費失敗"+payResult.getResult(), Toast.LENGTH_SHORT).show();
			}
		}
	}

	private String getOrderInfo(String subject, String body, String price) {
		// 簽約合作者身份ID
		String orderInfo = "partner=" + "\"" + AlipayConstants.PARTNER + "\"";
		// 簽約賣家支付寶賬號
		orderInfo += "&seller_id=" + "\"" + AlipayConstants.SELLER + "\"";
		// 商戶網站唯一訂單號
		orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";
		// 商品名稱
		orderInfo += "&subject=" + "\"" + subject + "\"";
		// 商品詳情
		orderInfo += "&body=" + "\"" + body + "\"";
		// 商品金額
		orderInfo += "&total_fee=" + "\"" + price + "\"";
		// 服務器異步通知頁面路徑
		orderInfo += "¬ify_url=" + "\"" + "http://notify.msp.hk/notify.htm" + "\"";
		// 服務接口名稱, 固定值
		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;
	}

	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;
	}

	private String sign(String content) {
		return SignUtils.sign(content, AlipayConstants.RSA_PRIVATE);
	}

	private String getSignType() {
		return "sign_type=\"RSA\"";
	}

}


微信支付

交易流程

微信支付的流程分為六個步驟:
1、使用開發者申請到的APP_ID和APP_SECRET向微信平台請求獲取access_token;
2、封裝訂單信息(使用開發者申請到的PARTNER_ID和PARTNER_KEY),並對訂單信息進行MD5摘要處理;
3、把加密後的訂單與access_token發給微信平台,生成預支付訂單,返回預付訂單id;
4、重新封裝訂單信息,加上預付訂單id,向微信平台發起支付交易;
5、微信sdk跳到微信支付頁面,用戶輸入支付帳號信息,提交支付;
6、支付完成,進行回調操作;


集成步驟

微信支付的集成與微信分享類似,有關微信分享的介紹參見《Android開發筆記(一百零五)社會化分享SDK》。下面是集成微信支付時的注意點:
1、要導入專門用於支付的jar包libammsdk.jar,注意這裡不能直接用微信分享的jar包,得用官方demo裡面的jar包;
2、申請的appid要與工程名對應,appid也要與app打包的簽名相對應;
3、回調代碼WXPayEntryActivity.java必須放在“包名.wxapi”這個package下面,另外AndroidManifest.xml也要補充該Activity的配置;


測試帳號

下面是微信開放平台官方demo給的測試帳號:
    // APP_ID 替換為你的應用從官方網站申請到的合法appId
    public static final String APP_ID = "wxd930ea5d5a258f4f";
    public static final String APP_SECRET = "db426a9829e4b49a0dcac7b4162da6b6";
    // wxd930ea5d5a258f4f 對應的支付密鑰
    public static final String APP_KEY = "L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K";
    
    /** 商家向財付通申請的商家id */
    public static final String PARTNER_ID = "1900000109";
    public static final String PARTNER_KEY = "8934e7d15453e97507ef794cf7b0519d";


下面是微信支付的效果截圖
\


下面是微信支付的示例代碼
1、獲取入口token
import com.example.exmpay.wechat.bean.WechatConstants;
import com.example.exmpay.wechat.bean.GetAccessTokenResult;
import com.example.exmpay.wechat.bean.LocalRetCode;
import com.example.exmpay.wechat.util.WechatUtil;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

public class GetAccessTokenTask extends AsyncTask {

	private static final String TAG = "GetAccessTokenTask";
	private Context context;
	private ProgressDialog dialog;
	
	public GetAccessTokenTask(Context context) {
		this.context = context;
	}
	
	@Override
	protected void onPreExecute() {
		dialog = ProgressDialog.show(context, "提示", "正在獲取access token...");
	}

	@Override
	protected GetAccessTokenResult doInBackground(Void... params) {
		GetAccessTokenResult result = new GetAccessTokenResult();
		String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
				WechatConstants.APP_ID, WechatConstants.APP_SECRET);
		Log.d(TAG, "get access token, url = " + url);
		
		byte[] buf = WechatUtil.httpGet(url);
		if (buf == null || buf.length == 0) {
			result.localRetCode = LocalRetCode.ERR_HTTP;
			return result;
		}
		
		String content = new String(buf);
		result.parseFrom(content);
		return result;
	}

	@Override
	protected void onPostExecute(GetAccessTokenResult result) {
		if (dialog != null) {
			dialog.dismiss();
		}
		
		if (result.localRetCode == LocalRetCode.ERR_OK) {
			Toast.makeText(context, "獲取access token成功, accessToken = " + result.accessToken, Toast.LENGTH_LONG).show();
			GetPrepayIdTask getPrepayId = new GetPrepayIdTask(context, result.accessToken);
			getPrepayId.execute();
		} else {
			Toast.makeText(context, "獲取access token失敗,原因: " + result.localRetCode.name(), Toast.LENGTH_LONG).show();
		}
	}
}


2、獲取預支付訂單與進行支付
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Random;

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;

import com.alibaba.fastjson.JSONObject;
import com.example.exmpay.wechat.bean.WechatConstants;
import com.example.exmpay.wechat.bean.GetPrepayIdResult;
import com.example.exmpay.wechat.bean.LocalRetCode;
import com.example.exmpay.wechat.util.MD5;
import com.example.exmpay.wechat.util.WechatUtil;
import com.tencent.mm.sdk.modelpay.PayReq;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

public class GetPrepayIdTask extends AsyncTask {

	private static final String TAG = "GetPrepayIdTask";
	private Context context;
	private ProgressDialog dialog;
	private String accessToken;
	
	public GetPrepayIdTask(Context context, String accessToken) {
		this.context = context;
		this.accessToken = accessToken;
	}
	
	@Override
	protected void onPreExecute() {
		dialog = ProgressDialog.show(context, "提示", "正在獲取預支付訂單...");
	}

	@Override
	protected GetPrepayIdResult doInBackground(Void... params) {
		String url = String.format("https://api.weixin.qq.com/pay/genprepay?access_token=%s", accessToken);
		String entity = genProductArgs();
		Log.d(TAG, "doInBackground, url = " + url + ", entity = " + entity);
		
		GetPrepayIdResult result = new GetPrepayIdResult();
		byte[] buf = WechatUtil.httpPost(url, entity);
		if (buf == null || buf.length == 0) {
			result.localRetCode = LocalRetCode.ERR_HTTP;
			return result;
		}
		
		String content = new String(buf);
		Log.d(TAG, "doInBackground, response content = " + content);
		result.parseFrom(content);
		return result;
	}

	@Override
	protected void onPostExecute(GetPrepayIdResult result) {
		if (dialog != null) {
			dialog.dismiss();
		}
		if (result.localRetCode == LocalRetCode.ERR_OK) {
			Toast.makeText(context, "獲取prepayid成功", Toast.LENGTH_LONG).show();
			payWithWechat(result);
		} else {
			Toast.makeText(context, "獲取prepayid失敗,原因"+result.localRetCode.name(), Toast.LENGTH_LONG).show();
		}
	}

	

	private IWXAPI mWeixinApi;
	
//	// 如果獲取token和預付標識在服務器實現,只留下支付動作在客戶端實現,那麼下面要異步調用
//	private void payWithWechat() {
//		final String payInfo = "";
//
//		Runnable payRunnable = new Runnable() {
//			@Override
//			public void run() {
//				sendWXPayReq(payInfo);
//			}
//		};
//		
//		Thread payThread = new Thread(payRunnable);
//		payThread.start();
//	}

	private String genPackage(List params) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(WechatConstants.PARTNER_KEY); // 注意:不能hardcode在客戶端,建議genPackage這個過程都由服務器端完成
		
		// 進行md5摘要前,params內容為原始內容,未經過url encode處理
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(Locale.getDefault());
		return URLEncodedUtils.format(params, "utf-8") + "&sign=" + packageSign;
	}
	
	private String genNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}
	
	private long genTimeStamp() {
		return System.currentTimeMillis() / 1000;
	}

	private String getTraceId() {
		return "crestxu_" + genTimeStamp(); 
	}

	private String genOutTradNo() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}
	
	private long timeStamp;
	private String nonceStr, packageValue; 
	
	private String genSign(List params) {
		StringBuilder sb = new StringBuilder();
		
		int i = 0;
		for (; i < params.size() - 1; i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append(params.get(i).getName());
		sb.append('=');
		sb.append(params.get(i).getValue());
		
		String sha1 = WechatUtil.sha1(sb.toString());
		Log.d(TAG, "genSign, sha1 = " + sha1);
		return sha1;
	}
	
	private String genProductArgs() {
		JSONObject json = new JSONObject();
		
		try {
			json.put("appid", WechatConstants.APP_ID);
			String traceId = getTraceId();  // traceId 由開發者自定義,可用於訂單的查詢與跟蹤,建議根據支付用戶信息生成此id
			json.put("traceid", traceId);
			nonceStr = genNonceStr();
			json.put("noncestr", nonceStr);
			
			List packageParams = new LinkedList();
			packageParams.add(new BasicNameValuePair("bank_type", "WX"));
			packageParams.add(new BasicNameValuePair("body", "千足金箍棒"));
			packageParams.add(new BasicNameValuePair("fee_type", "1"));
			packageParams.add(new BasicNameValuePair("input_charset", "UTF-8"));
			packageParams.add(new BasicNameValuePair("notify_url", "http://weixin.qq.com"));
			packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo()));
			packageParams.add(new BasicNameValuePair("partner", WechatConstants.PARTNER_ID));
			packageParams.add(new BasicNameValuePair("spbill_create_ip", "196.168.1.1"));
			packageParams.add(new BasicNameValuePair("total_fee", "1"));
			packageValue = genPackage(packageParams);
			
			json.put("package", packageValue);
			timeStamp = genTimeStamp();
			json.put("timestamp", timeStamp);
			
			List signParams = new LinkedList();
			signParams.add(new BasicNameValuePair("appid", WechatConstants.APP_ID));
			signParams.add(new BasicNameValuePair("appkey", WechatConstants.APP_KEY));
			signParams.add(new BasicNameValuePair("noncestr", nonceStr));
			signParams.add(new BasicNameValuePair("package", packageValue));
			signParams.add(new BasicNameValuePair("timestamp", String.valueOf(timeStamp)));
			signParams.add(new BasicNameValuePair("traceid", traceId));
			json.put("app_signature", genSign(signParams));
			
			json.put("sign_method", "sha1");
		} catch (Exception e) {
			Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage());
			return null;
		}
		
		return json.toString();
	}

	private void payWithWechat(GetPrepayIdResult result) {
		PayReq req = new PayReq();
		req.appId = WechatConstants.APP_ID;
		req.partnerId = WechatConstants.PARTNER_ID;
		req.prepayId = result.prepayId;
		req.nonceStr = nonceStr;
		req.timeStamp = String.valueOf(timeStamp);
		req.packageValue = "Sign=" + packageValue;
		
		List signParams = new LinkedList();
		signParams.add(new BasicNameValuePair("appid", req.appId));
		signParams.add(new BasicNameValuePair("appkey", WechatConstants.APP_KEY));
		signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
		signParams.add(new BasicNameValuePair("package", req.packageValue));
		signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
		signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
		signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
		req.sign = genSign(signParams);

		mWeixinApi = WXAPIFactory.createWXAPI(context, WechatConstants.APP_ID);
		// 在支付之前,如果應用沒有注冊到微信,應該先調用IWXMsg.registerApp將應用注冊到微信
		mWeixinApi.sendReq(req);
	}
}


3、完成支付後的回調
import net.sourceforge.simcpux.R;

import com.example.exmpay.wechat.bean.WechatConstants;
import com.tencent.mm.sdk.constants.ConstantsAPI;
import com.tencent.mm.sdk.modelbase.BaseReq;
import com.tencent.mm.sdk.modelbase.BaseResp;
import com.tencent.mm.sdk.modelbase.BaseResp.ErrCode;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

	private static final String TAG = "WXPayEntryActivity";
	private IWXAPI api;
	private TextView tv_result;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.pay_result);
		tv_result = (TextView) findViewById(R.id.tv_result);
		api = WXAPIFactory.createWXAPI(this, WechatConstants.APP_ID);
		api.handleIntent(getIntent(), this);
	}

	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);
		setIntent(intent);
		api.handleIntent(intent, this);
	}

	@Override
	public void onReq(BaseReq req) {
	}

	@Override
	public void onResp(BaseResp resp) {
		Log.d(TAG, "onResp, errCode = " + resp.errCode);
		String result = "";
		if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
			switch (resp.errCode) {
			case ErrCode.ERR_OK:
				result = "微信支付成功";
				break;
			case ErrCode.ERR_COMM:
				result = "微信支付失敗:"+resp.errCode+","+resp.errStr;
				break;
			case ErrCode.ERR_USER_CANCEL:
				result = "微信支付取消:"+resp.errCode+","+resp.errStr;
				break;
			default:
				result = "微信支付未知異常:"+resp.errCode+","+resp.errStr;
				break;
			}
		}
		Toast.makeText(this, result, Toast.LENGTH_LONG).show();
		tv_result.setText(result);
	}

}


銀聯支付

交易流程

銀聯支付的流程步驟見下:
1、向銀聯平台申請一個交易流水號;
2、向商戶自己的後台發起付費交易(如果有自己後台的話);
3、使用交易流水號向銀聯平台發起支付請求;
4、銀聯sdk跳到銀聯支付頁面,用戶輸入銀行卡號、手機號碼及驗證碼,提交支付;
5、支付完成,進行回調處理,返回串裡有簽名信息,app要傳回商戶後台進行驗證,並確認交易;


集成步驟

銀聯支付的集成略微復雜,注意點如下:
1、libs目錄下加入jar包UPPayAssistEx.jar和UPPayPluginExPro.jar,以及so庫文件;
2、assets目錄下加入data.bin文件;
3、AndroidManifest.xml加入兩個銀聯頁面的定義,示例如下:
    	
        
        
    	
        
        
        
        
        
4、在啟動銀聯支付的Activity代碼中,重寫方法onActivityResult,對支付結果的返回包進行驗證處理;


測試帳號

銀聯支付的官方demo下載頁面是https://open.unionpay.com/ajweb/help/file,下面是官方demo的測試帳號:
銀行卡號:6226090000000048
手機號:18100000000
短信驗證碼:123456(先點獲取驗證碼之後再輸入)


下面是銀聯支付的效果截圖
輸入銀行卡號
\


輸入手機號碼與驗證碼
\


下面是銀聯支付的示例代碼
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import org.json.JSONException;
import org.json.JSONObject;

import com.example.exmpay.unionpay.bean.UnionpayConstants;
import com.unionpay.UPPayAssistEx;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

public class UnionpayTask extends AsyncTask {

	private static final String TAG = "UnionpayTask";
	private Context context;
	private ProgressDialog dialog;

    public static final int PLUGIN_VALID = 0;
    public static final int PLUGIN_NOT_INSTALLED = -1;
    public static final int PLUGIN_NEED_UPGRADE = 2;
	
	public UnionpayTask(Context context) {
		this.context = context;
	}
	
	@Override
	protected void onPreExecute() {
		dialog = ProgressDialog.show(context, "提示", "正在啟動銀聯支付...");
	}

	@Override
	protected String doInBackground(Void... params) {
		Log.d(TAG, "doInBackground");
        String tn = null;
        InputStream is;
        try {

            String url = UnionpayConstants.TN_URL_01;

            URL myURL = new URL(url);
            URLConnection ucon = myURL.openConnection();
            ucon.setConnectTimeout(120000);
            is = ucon.getInputStream();
            int i = -1;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((i = is.read()) != -1) {
                baos.write(i);
            }

            tn = baos.toString();
            is.close();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

		Log.d(TAG, "tn="+tn);
		return tn;
	}

	@Override
	protected void onPostExecute(String tn) {
		if (dialog != null) {
			dialog.dismiss();
		}
		startpay(tn);
        UPPayAssistEx.startPay(context, null, null, tn, UnionpayConstants.MODE);
	}
	
	public static void dealResult(Context context, Intent data) {
        if (data == null) {
            return;
        }

        String msg = "";
        //支付控件返回字符串:success、fail、cancel 分別代表支付成功,支付失敗,支付取消
        String str = data.getExtras().getString("pay_result");
        if (str.equalsIgnoreCase("success")) {
            // 支付成功後,extra中如果存在result_data,取出校驗
            // result_data結構見c)result_data參數說明
            if (data.hasExtra("result_data")) {
                String result = data.getExtras().getString("result_data");
                Log.d(TAG, "result="+result);
                try {
                    JSONObject resultJson = new JSONObject(result);
                    String sign = resultJson.getString("sign");
                    String dataOrg = resultJson.getString("data");
                    // 驗簽證書同後台驗簽證書
                    // 此處的verify,商戶需送去商戶後台做驗簽
                    boolean ret = verify(dataOrg, sign, UnionpayConstants.MODE);
                    if (ret) {
                        // 驗證通過後,顯示支付結果
                        msg = "銀聯支付成功";
                    } else {
                        // 驗證不通過後的處理
                        // 建議通過商戶後台查詢支付結果
                        msg = "銀聯支付失敗:驗證失敗";
                    }
                } catch (JSONException e) {
                }
            } else {
                // 未收到簽名信息
                // 建議通過商戶後台查詢支付結果
                msg = "銀聯支付成功,但未收到簽名信息";
            }
        } else if (str.equalsIgnoreCase("fail")) {
            msg = "銀聯支付失敗";
        } else if (str.equalsIgnoreCase("cancel")) {
            msg = "銀聯支付取消";
        }
		Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
	}

	private int startpay(String tn) {
		//商戶後台要保存交易流水號
        return 0;
    }

    private static boolean verify(String msg, String sign64, String mode) {
        // 此處的verify,商戶需送去商戶後台做驗簽
        return true;
    }

}

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved