android 集成支付寶app支付(原生態)-包括android前端與java後臺
本文講解了 android開發的原生態app集成了支付寶支付, 還提供了java後臺服務器處理支付寶支付的加密代碼, app前端與java後臺服務器使用json數據格式交互信息,java後臺服務主要用來對支付數據進行加密和接受支付寶服務器的回調
註意: 本文即涉及到 android前端, 也涉及到 Java後臺
準備條件:
-
到支付寶官網上註冊用戶, 打開開放平臺,支付寶默認生成沙箱環境,用來測試支付流程
-
安裝Android Studio【下載】, 安裝 Eclipse mars 【下載】, JDK1.7 tomcat7
1. 支付流程概述
使用過app支付的用戶都知道,在支付環節,如果選擇【支付寶支付】,我們的app會拉起支付寶app,並且將支付信息傳入到
支付寶app中顯示出來, 用戶確認付款完成付款操作, 有朋友就會問,那我們的應用邏輯應該放在哪個步驟呢?
步驟1: 應用程序拉起支付寶app前,會按照支付寶的規則傳遞相應的數據給支付寶,所以啟動支付寶前,我們需要構建數據, 基本數據包括商品描述,商品價錢等,但為了讓支付寶區別是哪個應用程序傳過來的數據,還需要AppId(應用程序在支付寶平臺上對應的序號); 另外為了保障數據不被篡改,我們傳遞的數據需要進行RSA加密
步驟2: 對數據的加密工作是放在後臺進行的,那為什麽不放在前臺呢,熟悉RSA加密的朋友都知道,RSA是非對稱加密,加密方與解密方 需要一對密鑰(公鑰和私鑰), 這些公鑰與私鑰是敏感信息,放在android端容易被盜取,所以將公鑰與私鑰放在後臺,後臺對數據加密完成後再傳給前臺
步驟3: 前臺將加密完成後的數據傳送給支付寶,由支付寶完成支付
步驟4: 支付完成後app端會得到相應的事件通知,前臺根據相應的事件來判斷前臺的業務走向
步驟5: 支付寶官方要求,使用支付寶完成支付後,支付寶後臺 會調用 應用服務的後臺用來告之交易支付是否真正成功
由於本地服務無法向外界提供服務, 所以支付寶回調本地測試的服務器接口無法連通,至於連通的方法,可以看一下
ngrok的配置, 這個工具可以穿透內網
2. Android端
項目運行後如下圖
2.1 下載導入項目到android studio中,將build.gradle中的storeFile的路徑設置正確
2.2 android端的通信使用 retrofit rxjava技術,所以訪問後臺的請求url需要配置正確, 如果使用本文提供的後臺,則可以不必修改,如果使用別人的後臺服務,需要進行更改
3.3 android端訪問後臺獲取加密數據,然後將加密數據傳遞給支付寶
註意:由於使用的支付寶的沙箱配置信息 ,必須加上 代碼 EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
如果使用正式環境的支付寶配置信息, 不能加上上面沙箱代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
private void aliPay(){
BizContent bizContent = new BizContent();
bizContent.setOut_trade_no(outTradeNum);
bizContent.setTotal_amount(totalPrice);
bizContent.setSubject( "某個項目" + "-支付訂單" );
String strBizContent = new Gson().toJson(bizContent);
//generateOrderInfo去後臺獲取加密的信息
payService
.generateOrderInfo(strBizContent)
.subscribe( new Action1<String>() {
@Override
public void call(String s) {
//orderInfo為加密的信息
final String orderInfo = s;
Runnable payRunnable = new Runnable() {
@Override
public void run() {
//沙箱環境開啟沙箱功能
//正式環境不需要下面這行代碼
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
PayTask alipay = new PayTask(MainActivity. this );
Map<String, String> result = alipay.payV2(orderInfo, true );
Log.i( "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();
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
showToast(throwable.getMessage());
}
});
}
|
3.4 支付寶支付完成後執行 handleMessage
在handleMessage判斷支付情況, 如果 payResult.getResultStatus() == "9000" 則支付成功, 否則失敗
具體的失敗信息可以查看支付寶的官方文檔
@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")) { outTradeNum = ""; showToast("支付成功"); } else { outTradeNum = ""; // 該筆訂單真實的支付結果,需要依賴服務端的異步通知。 Toast.makeText(MainActivity.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 // 傳入,則支付賬戶為該授權賬戶 Toast.makeText(MainActivity.this, "授權成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT) .show(); } else { // 其他狀態值則為授權失敗 Toast.makeText(MainActivity.this, "授權失敗" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show(); } break; } default: break; } }; };
3. Java後臺
3.1 修改支付寶配置信息, 實例中使用的是本人支付寶中申請的沙箱配置信息
請將Config.properties中的信息改成自己的
3.2 generateOrderInfo對android傳遞的支付信息進行加密, 加密信息回傳給android端
@RequestMapping("/generateOrderInfo.htm") @ResponseBody public Result generateOrderInfo(String bizContent) { Result result = new Result(); AlipaySignature sing= new AlipaySignature(); if(StringUtils.isEmpty(bizContent)){ result.setData(""); result.setStateCode(Constant.RESULT_FAILURE); result.setDesc("待加簽字符串不能為空"); }else { String appId = ConfigManager.getInstance().getConfigItem("APPID"); Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(appId, bizContent, true); String orderParam = OrderInfoUtil2_0.buildOrderParam(params); String privateKey = ConfigManager.getInstance().getConfigItem("ProjectPrivateKey"); String sign = OrderInfoUtil2_0.getSign(params, privateKey, true); final String orderInfo = orderParam + "&" + sign; result.setDesc("加簽成功"); result.setStateCode(Constant.RESULT_SUCCESS); result.setData(orderInfo); } return result; }
3.3 支付成功後,支付寶服務端回調後臺應用程序接口,用來告之支付是否成功
/** * 支付寶的回調接口 * @param request */ @RequestMapping("/notifyOrderInfo.htm") public void notifyOrderInfo(HttpServletRequest request){ if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) { Enumeration<?> pNames = request.getParameterNames(); Map<String, String> param = new HashMap<String, String>(); try { while (pNames.hasMoreElements()) { String pName = (String) pNames.nextElement(); param.put(pName, request.getParameter(pName)); } boolean signVerified = AlipaySignature.rsaCheckV1(param, ConfigManager.getInstance().getConfigItem("AlipayPublicKey"), AlipayConstants.CHARSET_UTF8); // 校驗簽名是否正確 if (signVerified) { // TODO 驗簽成功後 // 按照支付結果異步通知中的描述,對支付結果中的業務內容進行1\2\3\4二次校驗,校驗成功後在response中返回success,校驗失敗返回failure System.out.println("訂單支付成功:" + JSON.toJSONString(param)); } else { // TODO 驗簽失敗則記錄異常日誌,並在response中返回failure. } } catch (Exception e) { e.printStackTrace(); } } return; }
關於支付寶的其它接口的更加詳細信息,請參照 【服務端詳解】
DEMO下載:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=844
android 集成支付寶app支付(原生態)-包括android前端與java後臺