此項(xiàng)目已開(kāi)源 趕快來(lái)圍觀 Start支持下吧
【客戶端開(kāi)源地址-JPay】【服務(wù)端端開(kāi)源地址-在com.javen.alipay
包名下
】
上一篇詳細(xì)介紹了微信APP支付點(diǎn)擊這里
此篇文章來(lái)詳細(xì)介紹下支付寶APP支付
目錄
1柿祈、支付寶與微信對(duì)比(申請(qǐng)、費(fèi)率、結(jié)算周期)
2转唉、支付寶上線應(yīng)用
3粱快、支付寶App支付Android集成流程詳解
4恬砂、服務(wù)端實(shí)現(xiàn)(建議直接官方提供的服務(wù)端SDK)
5篡殷、客戶端實(shí)現(xiàn)
6瞬内、常見(jiàn)錯(cuò)誤解決方案(ALI40247卓箫、AL38173)
補(bǔ)充(20170513)? 支付寶APP支付可以使用沙箱環(huán)境測(cè)試载矿。如需開(kāi)啟測(cè)試模式只需要在OnCreate中添加如下代碼。沙箱環(huán)境測(cè)試APP支付中請(qǐng)使用沙箱版錢包測(cè)試:點(diǎn)擊開(kāi)發(fā)者中心-沙箱環(huán)境-沙箱工具
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
使用沙箱環(huán)境測(cè)試
1烹卒、支付寶與微信對(duì)比
申請(qǐng):【微信開(kāi)發(fā)平臺(tái)】注冊(cè)的郵箱不能與騰訊其他產(chǎn)品同號(hào)闷盔,需要開(kāi)發(fā)者資質(zhì)認(rèn)證(需要¥300,而且支付商戶與公眾號(hào)不公用)而支付寶只需要企業(yè)實(shí)名認(rèn)證旅急,其他質(zhì)料類似(營(yíng)業(yè)執(zhí)照逢勾、組織機(jī)構(gòu)代碼(現(xiàn)在都三證合一了))。
費(fèi)率:
【微信簽約匯率參考質(zhì)料】【支付寶簽約匯率參考質(zhì)料】
結(jié)算周期:
微信結(jié)算周期:話費(fèi)通訊藐吮、財(cái)經(jīng)資訊溺拱、股票軟件類、網(wǎng)絡(luò)虛擬服務(wù)以及互聯(lián)網(wǎng)相關(guān)行業(yè) T+7? 眾籌 T+3 其他T+1谣辞,結(jié)算款項(xiàng)自動(dòng)提現(xiàn)到商戶的結(jié)算賬戶迫摔,一般從結(jié)算日起3個(gè)工作日到賬(具體到賬時(shí)間視不同銀行到賬情況而定)
支付寶結(jié)算周期:及時(shí)到支付寶賬號(hào)
2、支付寶上線應(yīng)用
1泥从、注冊(cè)賬號(hào)并實(shí)名認(rèn)證
注冊(cè)賬號(hào)了沒(méi)有實(shí)名認(rèn)證進(jìn)入開(kāi)發(fā)平臺(tái)的管理中心會(huì)提示如下圖
實(shí)名認(rèn)證
為什么要實(shí)名認(rèn)證
商家認(rèn)證流程
2句占、創(chuàng)建應(yīng)用開(kāi)通支付并上線
官方文檔有詳細(xì)的介紹-創(chuàng)建應(yīng)用、配置應(yīng)用歉闰、上線應(yīng)用
【資源下載:App支付DEMO&SDK辖众、生成與配置密鑰】
資源下載匯總
簽名工具
注意簽名工具目錄不能包含中文
簽名工具的使用
上傳密鑰
這里上傳的是rsa_public_key.pemJava版簽名使用的密鑰是rsa_private_key_pkcs8.pem
3卓起、支付寶App支付Android集成流程詳解
官方文檔點(diǎn)擊這里
1、導(dǎo)入支付寶SDK 其中SDK在圖資源下載匯總的WS.APP_PAY_SDK_BASE_20.zip中
2凹炸、修改Manifest
在商戶應(yīng)用工程的AndroidManifest.xml文件里面添加聲明:
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind" >
android:name="com.alipay.sdk.auth.AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind" >
3戏阅、權(quán)限聲明
4、如需混洗啤它、添加混淆規(guī)則
在商戶應(yīng)用工程的proguard-project.txt里添加以下相關(guān)規(guī)則:
alipaySDK-xxxxx.jar根據(jù)下載的做響應(yīng)的修改
-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奕筐、支付接口調(diào)用
獲取PayTask支付對(duì)象調(diào)用支付(支付行為需要在獨(dú)立的非ui線程中執(zhí)行
)具體實(shí)現(xiàn)參考客戶端實(shí)現(xiàn),調(diào)用支付需要使用到orderInfo具體實(shí)現(xiàn)參考服務(wù)端實(shí)現(xiàn)变骡。
6离赫、支付結(jié)果獲取和處理
調(diào)用pay方法支付后,將通過(guò)2種途徑獲得支付結(jié)果:
1塌碌、同步返回商戶應(yīng)用客戶端通過(guò)當(dāng)前調(diào)用支付的Activity的Handler對(duì)象渊胸,通過(guò)它的回調(diào)函數(shù)獲取支付結(jié)果。
2台妆、異步通知商戶需要提供一個(gè)http協(xié)議的接口翎猛,包含在請(qǐng)求支付的入?yún)⒅校鋕ey對(duì)應(yīng)notify_url接剩。支付寶服務(wù)器在支付完成后切厘,會(huì)以POST方式調(diào)用notify_url傳輸數(shù)據(jù)。
4懊缺、服務(wù)端實(shí)現(xiàn)
代碼來(lái)自Demo 并做簡(jiǎn)單的封裝
具體實(shí)現(xiàn)截圖
設(shè)置支付寶業(yè)務(wù)參數(shù)
設(shè)置支付寶業(yè)務(wù)參數(shù)
注意:支付寶App支付不支持沙盒模式(此坑糾結(jié)了很長(zhǎng)時(shí)間)疫稿,使用沙盒模式會(huì)出現(xiàn)ALI40247錯(cuò)誤,文末有錯(cuò)誤的詳細(xì)說(shuō)明鹃两。
核心實(shí)現(xiàn)代碼如下
/**
* App支付
*/
public void appPay(){
String orderInfo;
try {
String body="我是測(cè)試數(shù)據(jù)";
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 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");
}
}
具體實(shí)現(xiàn)參考【開(kāi)源項(xiàng)目】
補(bǔ)充 使用支付服務(wù)端SDK實(shí)現(xiàn)獲取預(yù)付訂單
1腾降、先獲取到AlipayClient
alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPulicKey, signType);
2拣度、使用AlipayTradeAppPayRequest封裝請(qǐng)求
/**
* 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{
//實(shí)例化具體API對(duì)應(yīng)的request類,類名稱和接口名稱對(duì)應(yīng),當(dāng)前調(diào)用接口名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已經(jīng)封裝掉了公共參數(shù),這里只需要傳入業(yè)務(wù)參數(shù)螃壤。以下方法為sdk的model入?yún)⒎绞?model和biz_content同時(shí)存在的情況下取biz_content)抗果。
request.setBizModel(model);
request.setNotifyUrl(notifyUrl);
//這里和普通的接口調(diào)用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
return response;
}
3奸晴、控制器封裝數(shù)據(jù)給客戶端
/**
* app支付
*/
public void appPay(){
try {
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("我是測(cè)試數(shù)據(jù)");
model.setSubject("App支付測(cè)試-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");
}
}
服務(wù)端異步通知
/**
* App支付支付回調(diào)通知
* https://doc.open.alipay.com/docs/doc.htm?treeId=54&articleId=106370&
* docType=1#s3
*/
public void app_pay_notify() {
try {
// 獲取支付寶POST過(guò)來(lái)反饋信息
Map params = AliPayApi.toMap(getRequest());
for (Map.Entry entry : params.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// 切記alipaypublickey是支付寶的公鑰冤馏,請(qǐng)去open.alipay.com對(duì)應(yīng)應(yīng)用下查看。
// boolean AlipaySignature.rsaCheckV1(Map 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");
}
}
將異步通知的參數(shù)轉(zhuǎn)化為Map
/**
* 將異步通知的參數(shù)轉(zhuǎn)化為Map
* @param request
* @return
*/
public static Map toMap(HttpServletRequest request) {
System.out.println(">>>>" + request.getQueryString());
Map params = new HashMap();
Map requestParams = request.getParameterMap();
for (Iterator 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] + ",";
}
// 亂碼解決寄啼,這段代碼在出現(xiàn)亂碼時(shí)使用逮光。
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
return params;
}
5代箭、客戶端實(shí)現(xiàn)
客戶端請(qǐng)求此action返回orderInfo,默認(rèn)的訪問(wèn)地址為http://[域名或者IP]:端口號(hào)/[項(xiàng)目名稱]/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 {
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, "正在調(diào)起支付", Toast.LENGTH_SHORT).show();
IPayLogic.getIntance(mContext).startAliPay(orderInfo);
}else{
Log.d("PAY_GET", "返回錯(cuò)誤"+message);
//? ? ? ? ? ? ? ? ? ? Toast.makeText(mContext, "返回錯(cuò)誤:"+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);
}
}
支付接口調(diào)用
public void startAliPay(final String orderInfo){
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(mContext);
Map result = alipay.payV2(orderInfo, true);
Message msg = new Message();
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
客戶端通過(guò)回調(diào)函數(shù)獲取支付結(jié)果
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@SuppressWarnings("unchecked")
public void handleMessage(Message msg) {
PayResult payResult = new PayResult((Map) msg.obj);
System.out.println("alipay call "+payResult.toString());
String resultStatus = payResult.getResultStatus();
String memo = payResult.getMemo();
if (Constants.payListener !=null){
//返回狀態(tài)以及詳細(xì)的描述參考
// 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, "支付寶測(cè)試", Toast.LENGTH_SHORT).show();
Order order = new Order();
order.setBody("會(huì)員充值中心");
order.setParaTradeNo(System.currentTimeMillis()+"");
order.setTotalFee(20);
order.setAttach("json");//附加參數(shù)
order.setNofityUrl("http://www.xxxx.com");//支付成功服務(wù)端回調(diào)通知的地址
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("回調(diào)過(guò)來(lái)的狀態(tài)》"+alicode+" message>"+((message!=null && message.isEmpty())?"":message));
Toast.makeText(MainActivity.this, "回調(diào)過(guò)來(lái)的狀態(tài)》" + alicode, Toast.LENGTH_SHORT).show();
}
});
}
6涕刚、常見(jiàn)錯(cuò)誤解決方案
APP支付報(bào)錯(cuò)ALI40247處理方案
ALI40247的錯(cuò)誤
有2種情況 1嗡综、沒(méi)有權(quán)限 2、簽名失敗
可以查看論壇提供的這個(gè)解決方案
AL38173的錯(cuò)誤一般是參數(shù)問(wèn)題造成的,建議檢查請(qǐng)求參數(shù)杜漠,對(duì)照文檔查看极景,比如:參數(shù)少了、多了驾茴、亂碼盼樟、名稱不對(duì),還有必傳參數(shù)是否都請(qǐng)求提交給支付寶了等等.
如果在網(wǎng)上查閱質(zhì)料還未解決锈至,可以尋求阿里的在線支持【支持中心】
此項(xiàng)目已開(kāi)源 趕快來(lái)圍觀 Start支持下吧
【客戶端開(kāi)源地址-JPay】【服務(wù)端端開(kāi)源地址-在com.javen.alipay包名下】
作者:Javen205
鏈接:http://www.reibang.com/p/3d91248aea4b
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有晨缴。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處峡捡。