此項目已開源 趕快來圍觀 Start支持下吧
【客戶端開源地址-JPay】【服務端端開源地址-在com.javen.alipay
包名下】
上一篇詳細介紹了微信APP支付 點擊這里
此篇文章來詳細介紹下支付寶APP支付
目錄
1、支付寶與微信對比(申請、費率、結算周期)
2、支付寶上線應用
3、支付寶App支付Android集成流程詳解
4、服務端實現(建議直接官方提供的服務端SDK)
5、客戶端實現
6、常見錯誤解決方案(ALI40247、AL38173)
補充(20170513) 支付寶APP支付可以使用沙箱環境測試。如需開啟測試模式只需要在OnCreate
中添加如下代碼。沙箱環境測試APP支付中請使用沙箱版錢包測試:點擊開發者中心-沙箱環境-沙箱工具
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
1、支付寶與微信對比
申請:【微信開發平臺】注冊的郵箱不能與騰訊其他產品同號,需要開發者資質認證(需要¥300,而且支付商戶與公眾號不公用)而支付寶只需要企業實名認證,其他質料類似(營業執照、組織機構代碼(現在都三證合一了))。
費率:
【微信簽約匯率參考質料】【支付寶簽約匯率參考質料】
結算周期:
微信結算周期: 話費通訊、財經資訊、股票軟件類、網絡虛擬服務以及互聯網相關行業 T+7 眾籌 T+3 其他T+1,結算款項自動提現到商戶的結算賬戶,一般從結算日起3個工作日到賬(具體到賬時間視不同銀行到賬情況而定)
支付寶結算周期:及時到支付寶賬號
2、支付寶上線應用
1、注冊賬號并實名認證
注冊賬號了沒有實名認證進入開發平臺的管理中心會提示如下圖
2、創建應用開通支付并上線
注意簽名工具目錄不能包含中文
這里上傳的是
rsa_public_key.pem
Java版簽名使用的密鑰是rsa_private_key_pkcs8.pem
3、支付寶App支付Android集成流程詳解
官方文檔 點擊這里
1、導入支付寶SDK 其中SDK在圖資源下載匯總
的WS.APP_PAY_SDK_BASE_20.zip
中
2、修改Manifest
在商戶應用工程的AndroidManifest.xml文件里面添加聲明:
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind" >
</activity>
<activity
android:name="com.alipay.sdk.auth.AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind" >
</activity>
3、權限聲明
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
4、如需混洗、添加混淆規則
在商戶應用工程的proguard-project.txt里添加以下相關規則:
alipaySDK-xxxxx.jar
根據下載的做響應的修改
-libraryjars libs/alipaySDK-xxxxx.jar
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
5、支付接口調用
獲取PayTask支付對象調用支付(支付行為需要在獨立的非ui線程中執行
)具體實現參考客戶端實現
,調用支付需要使用到orderInfo
具體實現參考服務端實現
。
6、支付結果獲取和處理
調用pay方法支付后,將通過2種途徑獲得支付結果:
1、同步返回
商戶應用客戶端通過當前調用支付的Activity的Handler對象,通過它的回調函數獲取支付結果。
2、異步通知
商戶需要提供一個http協議的接口,包含在請求支付的入參中,其key對應notify_url。支付寶服務器在支付完成后,會以POST方式調用notify_url傳輸數據。
4、服務端實現
代碼來自Demo 并做簡單的封裝
設置支付寶業務參數
注意: 支付寶App支付不支持沙盒模式(此坑糾結了很長時間),使用沙盒模式會出現ALI40247 錯誤,文末有錯誤的詳細說明。
核心實現代碼如下
/**
* App支付
*/
public void appPay(){
String orderInfo;
try {
String body="我是測試數據";
String passback_params="123";
String subject="1";
String total_amount="0.01";
String notify_url="http://javen.ittun.com/alipay/pay_notify";
String appId;
String rsa_private;
if (isDebug) {
appId=prop.get("test_appId").trim();
rsa_private=prop.get("test_rsa_private").trim();
System.out.println("test。。。。");
}else {
appId=prop.get("appId").trim();
rsa_private=prop.get("rsa_private").trim();
}
System.out.println("appId:"+appId);
System.out.println("rsa_private:"+rsa_private);
BizContent content = new BizContent();
content.setBody(body);
content.setOut_trade_no(OrderInfoUtil2_0.getOutTradeNo());;
content.setPassback_params(passback_params);
content.setSubject(subject);
content.setTotal_amount(total_amount);
content.setProduct_code("QUICK_MSECURITY_PAY");
Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(appId,notify_url,content);
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
String sign = OrderInfoUtil2_0.getSign(params, rsa_private);
orderInfo = orderParam + "&" + sign;
log.info("orderInfo>"+orderInfo);
result.success(orderInfo);
renderJson(result);
} catch (Exception e) {
e.printStackTrace();
result.addError("system error");
}
}
具體實現參考【開源項目】
補充 使用支付服務端SDK實現獲取預付訂單
1、先獲取到AlipayClient
alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPulicKey, signType);
2、使用AlipayTradeAppPayRequest
封裝請求
/**
* App支付
* @param model
* @param notifyUrl
* @return
* @throws AlipayApiException
*/
public static String startAppPayStr(AlipayTradeAppPayModel model, String notifyUrl) throws AlipayApiException{
AlipayTradeAppPayResponse response = appPay(model,notifyUrl);
return response.getBody();
}
/**
* App 支付
* https://doc.open.alipay.com/docs/doc.htm?treeId=54&articleId=106370&docType=1
* @param model
* @param notifyUrl
* @return
* @throws AlipayApiException
*/
public static AlipayTradeAppPayResponse appPay(AlipayTradeAppPayModel model, String notifyUrl) throws AlipayApiException{
//實例化具體API對應的request類,類名稱和接口名稱對應,當前調用接口名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已經封裝掉了公共參數,這里只需要傳入業務參數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
request.setBizModel(model);
request.setNotifyUrl(notifyUrl);
//這里和普通的接口調用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
return response;
}
3、控制器封裝數據給客戶端
/**
* app支付
*/
public void appPay(){
try {
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("我是測試數據");
model.setSubject("App支付測試-By Javen");
model.setOutTradeNo(StringUtils.getOutTradeNo());
model.setTimeoutExpress("30m");
model.setTotalAmount("0.01");
model.setPassbackParams("callback params");
model.setProductCode("QUICK_MSECURITY_PAY");
String orderInfo = AliPayApi.startAppPayStr(model,AliPayApi.notify_domain+"/alipay/app_pay_notify");
result.success(orderInfo);
renderJson(result);
} catch (AlipayApiException e) {
e.printStackTrace();
result.addError("system error");
}
}
服務端異步通知
/**
* App支付支付回調通知
* https://doc.open.alipay.com/docs/doc.htm?treeId=54&articleId=106370&
* docType=1#s3
*/
public void app_pay_notify() {
try {
// 獲取支付寶POST過來反饋信息
Map<String, String> params = AliPayApi.toMap(getRequest());
for (Map.Entry<String, String> entry : params.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// 切記alipaypublickey是支付寶的公鑰,請去open.alipay.com對應應用下查看。
// boolean AlipaySignature.rsaCheckV1(Map<String, String> params,
// String publicKey, String charset, String sign_type)
boolean flag = AlipaySignature.rsaCheckV1(params, AliPayApi.ALIPAY_PUBLIC_KEY, AliPayApi.CHARSET,
AliPayApi.SIGN_TYPE);
if (flag) {
// TODO
System.out.println("success");
renderText("success");
return;
} else {
// TODO
System.out.println("failure");
renderText("failure");
}
} catch (AlipayApiException e) {
e.printStackTrace();
renderText("failure");
}
}
將異步通知的參數轉化為Map
/**
* 將異步通知的參數轉化為Map
* @param request
* @return
*/
public static Map<String, String> toMap(HttpServletRequest request) {
System.out.println(">>>>" + request.getQueryString());
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 亂碼解決,這段代碼在出現亂碼時使用。
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
return params;
}
5、客戶端實現
客戶端請求此action返回orderInfo,默認的訪問地址為
http://[域名或者IP]:端口號/[項目名稱]/alipay/appPay
成功將返回:
{
"code": 0,
"data": "charset=utf-8&biz_content=%7B%22out_trade_no%22%3A%22120822453414812%22%2C%22total_amount%22%3A%220.01%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22passback_params%22%3A%22123%22%7D&method=alipay.trade.app.pay&format=json¬ify_url=http%3A%2F%2Fjaven.ittun.com%2Falipay%2Fpay_notify&app_id=2016102000727659&sign_type=RSA&version=1.0×tamp=2016-12-08+22%3A45%3A34&sign=m6fpNI58jkOIHROtm8Q2V1Ei7bxXc14JHtJEeqGM0B8dWlq3d%2FfAqpoQTZgeBb%2FVK%2B%2BydOJzVvSWc89dBxhYUq72KOeUwHiKlRJBFMnEMAZbJlRxqu9%2BRX2q7HSRmA6WRg75O68HZhkIhtO3bSNx3s710tMHmQCN230JoVWiwHw%3D",
"message": null
}
/**
* 獲取支付寶App支付訂單信息
* @return
*/
public String getAliPayOrderInfo(Order order){
String result=HttpKit.get(Constants.ALIPAY_URL);
return result;
}
異步獲取orderInfo
public class AliPay extends AsyncTask<Object, Integer, String> {
private Activity mContext;
public AliPay(Activity context) {
this.mContext = context;
}
@Override
protected String doInBackground(Object... params) {
return IPayLogic.getIntance(mContext).getAliPayOrderInfo((Order)params[0]);
}
@Override
protected void onPostExecute(String result) {
try {
if (result!=null) {
System.out.println("AliPay result>"+result);
JSONObject data = new JSONObject(result);
String message = data.getString("message");
int code = data.getInt("code");
if(code == 0){
String orderInfo = data.getString("data");
Toast.makeText(mContext, "正在調起支付", Toast.LENGTH_SHORT).show();
IPayLogic.getIntance(mContext).startAliPay(orderInfo);
}else{
Log.d("PAY_GET", "返回錯誤"+message);
// Toast.makeText(mContext, "返回錯誤:"+message, Toast.LENGTH_SHORT).show();
}
}else {
System.out.println("get AliPay exception, is null");
}
} catch (Exception e) {
Log.e("PAY_GET", "異常:"+e.getMessage());
Toast.makeText(mContext, "異常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
super.onPostExecute(result);
}
}
支付接口調用
public void startAliPay(final String orderInfo){
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(mContext);
Map<String, String> result = alipay.payV2(orderInfo, true);
Message msg = new Message();
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
客戶端通過回調函數獲取支付結果
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@SuppressWarnings("unchecked")
public void handleMessage(Message msg) {
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
System.out.println("alipay call "+payResult.toString());
String resultStatus = payResult.getResultStatus();
String memo = payResult.getMemo();
if (Constants.payListener !=null){
//返回狀態以及詳細的描述參考
// https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.xN1NnL&treeId=204&articleId=105302&docType=1
Constants.payListener.onPay(-2,resultStatus,memo);
}
}
};
客戶端具體使用方法
public void testAliPay(View view){
Toast.makeText(this, "支付寶測試", Toast.LENGTH_SHORT).show();
Order order = new Order();
order.setBody("會員充值中心");
order.setParaTradeNo(System.currentTimeMillis()+"");
order.setTotalFee(20);
order.setAttach("json");//附加參數
order.setNofityUrl("http://www.xxxx.com");//支付成功服務端回調通知的地址
IPay.getIntance(MainActivity.this).toPay(IPay.PayMode.ALIPAY,order,new IPay.IPayListener() {
@Override
public void onPay(int wxcode, String alicode, String message) {
System.out.println("回調過來的狀態》"+alicode+" message>"+((message!=null && message.isEmpty())?"":message));
Toast.makeText(MainActivity.this, "回調過來的狀態》" + alicode, Toast.LENGTH_SHORT).show();
}
});
}
6、常見錯誤解決方案
APP支付報錯ALI40247處理方案
ALI40247的錯誤
**有2種情況 1、沒有權限 2、簽名失敗 **
可以查看論壇提供的這個解決方案
AL38173的錯誤一般是參數問題造成的,建議檢查請求參數,對照文檔查看,比如:參數少了、多了、亂碼、名稱不對,還有必傳參數是否都請求提交給支付寶了等等.
如果在網上查閱質料還未解決,可以尋求阿里的在線支持【支持中心】
此項目已開源 趕快來圍觀 Start支持下吧
【客戶端開源地址-JPay】【服務端端開源地址-在com.javen.alipay
包名下】
推薦閱讀
Android版-微信APP支付
極速開發微信公眾號之微信買單
極速開發微信公眾號之公眾號支付
極速開發微信公眾號之掃碼支付
極速開發微信公眾號之刷卡支付
極速開發微信公眾號之現金紅包
記錄學習的點滴,以此勉勵不斷奮斗的自己?????? 如果對你有幫助記得點喜歡告訴我哈