首先是OrderInfoUtil2_0這個基礎類。後面調用的不少方法都抽出來了集成在這個類裏面,就當這個是一個工具類吧。web
public class OrderInfoUtil2_0 { express
/** * 構造受權參數列表 * * @param pid * @param app_id * @param target_id * @return */ public static Map<String, String> buildAuthInfoMap(String pid, String app_id, String target_id) { Map<String, String> keyValues = new HashMap<String, String>(); // 商戶簽約拿到的app_id,如:2013081700024223 keyValues.put("app_id", app_id); // 商戶簽約拿到的pid,如:2088102123816631 keyValues.put("pid", pid); // 服務接口名稱, 固定值 keyValues.put("apiname", "com.alipay.account.auth"); // 商戶類型標識, 固定值 keyValues.put("app_name", "mc"); // 業務類型, 固定值 keyValues.put("biz_type", "openservice"); // 產品碼, 固定值 keyValues.put("product_id", "APP_FAST_LOGIN"); // 受權範圍, 固定值 keyValues.put("scope", "kuaijie"); // 商戶惟一標識,如:kkkkk091125 keyValues.put("target_id", target_id); // 受權類型, 固定值 keyValues.put("auth_type", "AUTHACCOUNT"); // 簽名類型 keyValues.put("sign_type", "RSA"); return keyValues; } /** * 構造支付訂單參數列表 * * @return */ public static Map<String, String> buildOrderParamMap(String app_id, String total_amount, String product_info, String time,String out_trade_no) { Map<String, String> keyValues = new HashMap<String, String>(); keyValues.put("app_id", app_id); keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\"" + total_amount + "\",\"subject\":\"" + product_info + "\",\"body\":\"兌換\",\"out_trade_no\":\"" +out_trade_no + "\"}"); keyValues.put("charset", "utf-8"); keyValues.put("method", "alipay.trade.app.pay"); keyValues.put("sign_type", "RSA"); keyValues.put("timestamp", time);// "2016-07-29 16:55:53" keyValues.put("version", "1.0"); keyValues.put("notify_url", "成功回調地址"); return keyValues; } /** * 構造支付訂單參數信息 * * @param map 支付訂單參數 * @return */ public static String buildOrderParam(Map<String, String> map) { List<String> keys = new ArrayList<String>(map.keySet()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < keys.size() - 1; i++) { String key = keys.get(i); String value = map.get(key); sb.append(buildKeyValue(key, value, true)); sb.append("&"); } String tailKey = keys.get(keys.size() - 1); String tailValue = map.get(tailKey); sb.append(buildKeyValue(tailKey, tailValue, true)); return sb.toString(); } /** * 拼接鍵值對 * * @param key * @param value * @param isEncode * @return */ private static String buildKeyValue(String key, String value, boolean isEncode) { StringBuilder sb = new StringBuilder(); sb.append(key); sb.append("="); if (isEncode) { try { sb.append(URLEncoder.encode(value, "UTF-8")); } catch (UnsupportedEncodingException e) { sb.append(value); } } else { sb.append(value); } return sb.toString(); } /** * 對支付參數信息進行簽名 * * @param map 待簽名受權信息 * @return */ public static String getSign(Map<String, String> map, String rsaKey) { List<String> keys = new ArrayList<String>(map.keySet()); // key排序 Collections.sort(keys); StringBuilder authInfo = new StringBuilder(); for (int i = 0; i < keys.size() - 1; i++) { String key = keys.get(i); String value = map.get(key); authInfo.append(buildKeyValue(key, value, false)); authInfo.append("&"); } String tailKey = keys.get(keys.size() - 1); String tailValue = map.get(tailKey); authInfo.append(buildKeyValue(tailKey, tailValue, false)); String oriSign = SignUtils.sign(authInfo.toString(), rsaKey); String encodedSign = ""; try { encodedSign = URLEncoder.encode(oriSign, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return "sign=" + encodedSign; } /** * 要求外部訂單號必須惟一。 * * @return */ private static 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; } }
/** * 重要說明: * <p/> * 這裏只是爲了方便直接向商戶展現支付寶的整個支付流程;因此Demo中加簽過程直接放在客戶端完成; * 真實App裏,privateKey等數據嚴禁放在客戶端,加簽過程務必要放在服務端完成; * 防止商戶私密數據泄露,形成沒必要要的資金損失,及面臨各類安全風險; */ public class PayDemoActivity extends FragmentActivity { /** * 支付寶支付業務:入參app_id */ public static final String APPID = "入參app_id"; /** * 支付寶帳戶登陸受權業務:入參pid值 */ public static final String PID = "入參pid值"; /** * 支付寶帳戶登陸受權業務:入參target_id值 */ public static final String TARGET_ID = "入參target_id值"; /** * 商戶私鑰,pkcs8格式 */ public static final String RSA_PRIVATE = "商戶私鑰"; private static final int SDK_PAY_FLAG = 1; private static final int SDK_AUTH_FLAG = 2; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @SuppressWarnings("unused") public void handleMessage(Message msg) { switch (msg.what) { case SDK_PAY_FLAG: { @SuppressWarnings("unchecked") PayResult payResult = new PayResult((Map<String, String>) msg.obj); /** 對於支付結果,請商戶依賴服務端的異步通知結果。同步通知結果,僅做爲支付結束的通知。 */ String resultInfo = payResult.getResult();// 同步返回須要驗證的信息 String resultStatus = payResult.getResultStatus(); // 判斷resultStatus 爲9000則表明支付成功 if (TextUtils.equals(resultStatus, "9000")) { // 該筆訂單是否真實支付成功,須要依賴服務端的異步通知。 MyToast.makeText(PayDemoActivity.this, "支付成功", Toast.LENGTH_SHORT).show(); } else { // 該筆訂單真實的支付結果,須要依賴服務端的異步通知。 MyToast.makeText(PayDemoActivity.this, "支付失敗", Toast.LENGTH_SHORT).show(); } break; } case SDK_AUTH_FLAG: { @SuppressWarnings("unchecked") AuthResult authResult = new AuthResult((Map<String, String>) msg.obj, true); String resultStatus = authResult.getResultStatus(); // 判斷resultStatus 爲「9000」且result_code // 爲「200」則表明受權成功,具體狀態碼錶明含義可參考受權接口文檔 if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) { // 獲取alipay_open_id,調支付時做爲參數extern_token 的value // 傳入,則支付帳戶爲該受權帳戶 MyToast.makeText(PayDemoActivity.this, "受權成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT) .show(); } else { // 其餘狀態值則爲受權失敗 MyToast.makeText(PayDemoActivity.this, "受權失敗" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show(); } break; } default: break; } } ; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pay_main); SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String date_e = dfs.format(new Date()); payV2("0.02", "團幣兌換", date_e); } /** * 支付寶支付業務 */ public void payV2(String price, String product_info, String time) { if (TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE)) { new AlertDialog.Builder(this).setTitle("警告").setMessage("須要配置APPID | RSA_PRIVATE") .setPositiveButton("肯定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialoginterface, int i) { finish(); } }).show(); return; } /** * 這裏只是爲了方便直接向商戶展現支付寶的整個支付流程;因此Demo中加簽過程直接放在客戶端完成; * 真實App裏,privateKey等數據嚴禁放在客戶端,加簽過程務必要放在服務端完成; * 防止商戶私密數據泄露,形成沒必要要的資金損失,及面臨各類安全風險; * * orderInfo的獲取必須來自服務端; */ // Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID, price, product_info, time); Map<String, String> params=new HashMap<String, String>(); String orderParam = OrderInfoUtil2_0.buildOrderParam(params); String sign = OrderInfoUtil2_0.getSign(params, RSA_PRIVATE); final String orderInfo = orderParam + "&" + sign; Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(PayDemoActivity.this); Map<String, String> result = alipay.payV2(orderInfo, true); Log.e("msp", result.toString()); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; Thread payThread = new Thread(payRunnable); payThread.start(); } /** * 支付寶帳戶受權業務 * * @param v */ public void authV2(View v) { if (TextUtils.isEmpty(PID) || TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE) || TextUtils.isEmpty(TARGET_ID)) { new AlertDialog.Builder(this).setTitle("警告").setMessage("須要配置PARTNER |APP_ID| RSA_PRIVATE| TARGET_ID") .setPositiveButton("肯定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialoginterface, int i) { } }).show(); return; } /** * 這裏只是爲了方便直接向商戶展現支付寶的整個支付流程;因此Demo中加簽過程直接放在客戶端完成; * 真實App裏,privateKey等數據嚴禁放在客戶端,加簽過程務必要放在服務端完成; * 防止商戶私密數據泄露,形成沒必要要的資金損失,及面臨各類安全風險; * * authInfo的獲取必須來自服務端; */ Map<String, String> authInfoMap = OrderInfoUtil2_0.buildAuthInfoMap(PID, APPID, TARGET_ID); String info = OrderInfoUtil2_0.buildOrderParam(authInfoMap); String sign = OrderInfoUtil2_0.getSign(authInfoMap, RSA_PRIVATE); final String authInfo = info + "&" + sign; Runnable authRunnable = new Runnable() { @Override public void run() { // 構造AuthTask 對象 AuthTask authTask = new AuthTask(PayDemoActivity.this); // 調用受權接口,獲取受權結果 Map<String, String> result = authTask.authV2(authInfo, true); Message msg = new Message(); msg.what = SDK_AUTH_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; // 必須異步調用 Thread authThread = new Thread(authRunnable); authThread.start(); } /** * get the sdk version. 獲取SDK版本號 */ public void getSDKVersion() { PayTask payTask = new PayTask(this); String version = payTask.getVersion(); MyToast.makeText(this, version, Toast.LENGTH_SHORT).show(); } /** * 原生的H5(手機網頁版支付切natvie支付) 【對應頁面網頁支付按鈕】 * * @param v */ public void h5Pay(View v) { Intent intent = new Intent(this, H5PayDemoActivity.class); Bundle extras = new Bundle(); /** * url是測試的網站,在app內部打開頁面是基於webview打開的,demo中的webview是H5PayDemoActivity, * demo中攔截url進行支付的邏輯是在H5PayDemoActivity中shouldOverrideUrlLoading方法實現, * 商戶能夠根據本身的需求來實現 */ String url = "http://m.taobao.com"; // url能夠是一號店或者淘寶等第三方的購物wap站點,在該網站的支付過程當中,支付寶sdk完成攔截支付 extras.putString("url", url); intent.putExtras(extras); startActivity(intent); } }
剩下就是支付寶支付的業務邏輯了。下面的out_trade_no是本身請求服務器返回過來的訂單號,time就是當前時間,product_info就是顯示在支付頁面上的字段,本身設定,試試就知道。api
/** * 支付寶支付業務 */ public void payV2(String price, String product_info, String time, String out_trade_no) { if (TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE)) { new AlertDialog.Builder(this).setTitle("警告").setMessage("須要配置APPID | RSA_PRIVATE") .setPositiveButton("肯定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialoginterface, int i) { finish(); } }).show(); return; } /** * 這裏只是爲了方便直接向商戶展現支付寶的整個支付流程;因此Demo中加簽過程直接放在客戶端完成; * 真實App裏,privateKey等數據嚴禁放在客戶端,加簽過程務必要放在服務端完成; * 防止商戶私密數據泄露,形成沒必要要的資金損失,及面臨各類安全風險; * * orderInfo的獲取必須來自服務端; */ Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID, price, product_info, time, out_trade_no); String orderParam = OrderInfoUtil2_0.buildOrderParam(params); String sign = OrderInfoUtil2_0.getSign(params, RSA_PRIVATE); final String orderInfo = orderParam + "&" + sign; Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(RechargeMoneyActivity.this); Map<String, String> result = alipay.payV2(orderInfo, true); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; Thread payThread = new Thread(payRunnable); payThread.start(); }
handler處理
安全
private Handler mHandler = new Handler() {服務器
@SuppressWarnings("unused") public void handleMessage(Message msg) { switch (msg.what) { case SDK_PAY_FLAG: { @SuppressWarnings("unchecked") PayResult payResult = new PayResult((Map<String, String>) msg.obj); /** 對於支付結果,請商戶依賴服務端的異步通知結果。同步通知結果,僅做爲支付結束的通知。 */ String resultInfo = payResult.getResult();// 同步返回須要驗證的信息 String memo = payResult.getMemo(); String resultStatus = payResult.getResultStatus(); // 判斷resultStatus 爲9000則表明支付成功 if (TextUtils.equals(resultStatus, "9000")) { // 該筆訂單是否真實支付成功,須要依賴服務端的異步通知。 // showHintDialog("支付成功"); } else { pay_state = "0"; } String sign = TGmd5.getMD5(logid + pay_state + memo); tuanbiExchangePresenter.doAlipay(logid, pay_state, memo, sign); break; } case SDK_AUTH_FLAG: { @SuppressWarnings("unchecked") AuthResult authResult = new AuthResult((Map<String, String>) msg.obj, true); String resultStatus = authResult.getResultStatus(); // 判斷resultStatus 爲「9000」且result_code // 爲「200」則表明受權成功,具體狀態碼錶明含義可參考受權接口文檔 if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) { // 獲取alipay_open_id,調支付時做爲參數extern_token 的value // 傳入,則支付帳戶爲該受權帳戶 MyToast.makeText(RechargeMoneyActivity.this, "受權成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT) .show(); } else { // 其餘狀態值則爲受權失敗 MyToast.makeText(RechargeMoneyActivity.this, "受權失敗" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show(); } break; } default: break; } } ; };
這樣一個支付寶支付就集成了,是否是很簡單。複製代碼就能寫出,注意裏面代碼註解。填寫各類id。app
源碼免費下載:http://www.jinhusns.com/Products/Download/?type=yhqdom