在開發的APP中項目集成了微信跟支付寶支付,分別是在訂單確認頁面,訂單列表以及訂單詳情裏面都須要進行支付,而且須要在當前界面處理支付結果,以前的處理是將代碼拷貝了三份,後來隨着項目愈來愈大,感受比較low,因而打算重構一下支付模塊,下面分享一下重構的整個過程。git
支付寶的集成比較簡單,按照官方文檔來集成,通常是比較順利的,不過我是2班的,當時作的時候簽名一直不成功,可是跟文檔是如出一轍的,後來無心中發現(由於有意沒發現)是orderInfo的拼接順序跟簽名的順序不同致使的,因此要麼在本地簽名,要麼在服務端簽名,千萬不要一邊拼接另外一邊簽名,這樣會致使orderInfo的拼接順序跟簽名的順序不同失敗,就呵呵了。github
由於實在一個類中,咱們只須要在修改AlipayActivity的構造方法的時候傳入一個接口,在支付寶支付返回給當前調用的界面就OK了,不論是Activity,Fragment,或者是Adapter都是能夠的api
在調試的時候不論是debug模式仍是release模式,均可以進行調試bash
支付寶有自帶的H5頁面,不安裝客戶端也能夠正常支付微信
相對於支付寶支付,微信支付就稍微麻煩一下,並且文檔資料比較少,必定要嚴格按照文檔的規範,否則出問題了,比較麻煩。app
微信支付比較坑的一點就是,他的回調必須是在固定的包名:項目包名+wxapi,並且名稱是WXPayEntryActivity。異步
因此開發的時候即便是debug模式也必須帶上簽名ide
必須進行校驗,否則他只會返回給你一個code,而後並不會告訴你爲何失敗,就是這麼任性微信支付
下面借用stay大神的What-How-Why的思路對這個支付方式進行了重構ui
定義一個基類,讓支付參數對象繼承這個基類;
public class BasePayBean implements Serializable {
}
複製代碼
public class AliPayBean extends BasePayBean {
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
private String code;
private String message;
private DataBean data;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public DataBean getData() {
return data;
}
public void setData(DataBean data) {
this.data = data;
}
public static class DataBean {
private String _input_charset;
private String body;
private String notify_url;
private String out_trade_no;
private String partner;
private String payment_type;
private String return_url;
private String seller_id;
private String service;
private String subject;
private String total_fee;
private String sign_string;
private String sign_type;
private String sign;
public String get_input_charset() {
return _input_charset;
}
public void set_input_charset(String _input_charset) {
this._input_charset = _input_charset;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getNotify_url() {
return notify_url;
}
public void setNotify_url(String notify_url) {
this.notify_url = notify_url;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getPartner() {
return partner;
}
public void setPartner(String partner) {
this.partner = partner;
}
public String getPayment_type() {
return payment_type;
}
public void setPayment_type(String payment_type) {
this.payment_type = payment_type;
}
public String getReturn_url() {
return return_url;
}
public void setReturn_url(String return_url) {
this.return_url = return_url;
}
public String getSeller_id() {
return seller_id;
}
public void setSeller_id(String seller_id) {
this.seller_id = seller_id;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getTotal_fee() {
return total_fee;
}
public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}
public String getSign_string() {
return sign_string;
}
public void setSign_string(String sign_string) {
this.sign_string = sign_string;
}
public String getSign_type() {
return sign_type;
}
public void setSign_type(String sign_type) {
this.sign_type = sign_type;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
}
}
複製代碼
public class WeChatBean extends BasePayBean {
private String code;
private String message;
private DataBean data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public DataBean getData() {
return data;
}
public void setData(DataBean data) {
this.data = data;
}
public static class DataBean {
private String appid;
private String partnerid;
private String prepayid;
private String package_;
private String noncestr;
private String timestamp;
private String sign;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getPartnerid() {
return partnerid;
}
public void setPartnerid(String partnerid) {
this.partnerid = partnerid;
}
public String getPrepayid() {
return prepayid;
}
public void setPrepayid(String prepayid) {
this.prepayid = prepayid;
}
public String getPackage_() {
return package_;
}
public void setPackage_(String package_) {
this.package_ = package_;
}
public String getNoncestr() {
return noncestr;
}
public void setNoncestr(String noncestr) {
this.noncestr = noncestr;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
}
複製代碼
定義一個泛型接口,讓支付對象去繼承這個接口
public interface BasePayWay<T extends BasePayBean> {
void startPay(Activity activity, T t, PayCallBack payCallback);
}
複製代碼
public class AliPayWay implements BasePayWay<AliPayBean> {
//商戶PID
public static final String PARTNER = "";
//商戶收款帳號
public static final String SELLER = "";
//商戶私鑰,pkcs8格式
public static String RSA_PRIVATE = "";
public static final int SDK_PAY_FLAG = 1;
public static final int SDK_CHECK_FLAG = 2;
public PayCallBack mPayCallBack;
private Activity mActivity;
//--------支付寶支付回調-----
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case AliPayWay.SDK_PAY_FLAG: {
PayResult payResult = new PayResult((String) msg.obj);
// 支付寶返回這次支付結果及加簽,建議對支付寶簽名信息拿簽約時支付寶提供的公鑰作驗籤
String resultStatus = payResult.getResultStatus();
// 判斷resultStatus 爲「9000」則表明支付成功,具體狀態碼錶明含義可參考接口文檔
if (TextUtils.equals(resultStatus, "9000")) {
mPayCallBack.onResponse(0);
} else {
// 判斷resultStatus 爲非「9000」則表明可能支付失敗
// 「8000」表明支付結果由於支付渠道緣由或者系統緣由還在等待支付結果確認,最終交易是否成功以服務端異步通知爲準(小几率狀態)
if (TextUtils.equals(resultStatus, "8000")) {
Toast.makeText(mActivity, "支付結果確認中", Toast.LENGTH_SHORT).show();
} else if (TextUtils.equals(resultStatus, "6001")) {
mPayCallBack.onResponse(-2);
} else {
// 其餘值就能夠判斷爲支付失敗,包括用戶主動取消支付,或者系統返回的錯誤
mPayCallBack.onResponse(-1);
}
}
break;
}
case AliPayWay.SDK_CHECK_FLAG: {
Toast.makeText(BaseApplication.getContext(), "檢查結果爲:" + msg.obj, Toast.LENGTH_SHORT).show();
break;
}
default:
break;
}
}
};
/**
* sign the order info. 對訂單信息進行簽名
*
* @param content 待簽名訂單信息
*/
public String sign(String content) {
return SignUtils.sign(content, RSA_PRIVATE);
}
/**
* get the sign type we use. 獲取簽名方式
*/
public String getSignType() {
return "sign_type=\"RSA\"";
}
@Override
public void startPay(Activity activity, AliPayBean aliPayBean, PayCallBack payCallback) {
this.mActivity = activity;
this.mPayCallBack = payCallback;
String orderInfo = aliPayBean.getData().getSign_string();
String sign = aliPayBean.getData().getSign();
try {
// 僅需對sign 作URL編碼
sign = URLEncoder.encode(sign, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 完整的符合支付寶參數規範的訂單信息
final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();
Log.d("payInfo------->", payInfo);
Runnable payRunnable = new Runnable() {
@Override
public void run() {
// 構造PayTask 對象
PayTask alipay = new PayTask(mActivity);
// 調用支付接口,獲取支付結果
String result = alipay.pay(payInfo, true);
Message msg = new Message();
msg.what = AliPayWay.SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必須異步調用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
}
複製代碼
public class WeChatWay implements BasePayWay<WeChatBean> {
private static WeChatWay mWeChatPay;
private IWXAPI api;
private Context mContext;
private PayCallBack mPayCallBack;
private static final int TIMELINE_SUPPORTED_VERSION = 0x21020001;
private WeChatWay(String wxAppId) {
api = WXAPIFactory.createWXAPI(mContext, null);
api.registerApp(wxAppId);
}
public static WeChatWay getInstance(String wxAppId) {
if (mWeChatPay == null) {
synchronized (WeChatWay.class) {
if (mWeChatPay == null) {
mWeChatPay = new WeChatWay(wxAppId);
}
}
}
return mWeChatPay;
}
public IWXAPI getApi() {
return api;
}
private boolean checkWeChatPay() {
int wxSdkVersion = api.getWXAppSupportAPI();
boolean isWeChatAble = true;
if (!api.isWXAppInstalled()) {
CommonUtils.showToast(mContext, "使用微信支付必須先安裝微信客戶端");
isWeChatAble = false;
} else if (wxSdkVersion < TIMELINE_SUPPORTED_VERSION) {
CommonUtils.showToast(mContext, "微信支付支持的最低版本高於當前安裝版本,請先升級微信客戶端");
isWeChatAble = false;
}
return isWeChatAble;
}
@Override
public void startPay(Activity activity, WeChatBean weChatBean, PayCallBack payCallback) {
mContext = activity.getApplicationContext();
this.mPayCallBack = payCallback;
if (checkWeChatPay()) {
PayReq req = new PayReq();
req.appId = weChatBean.getData().getAppid();
req.partnerId = weChatBean.getData().getPartnerid();
req.prepayId = weChatBean.getData().getPrepayid();
req.packageValue = weChatBean.getData().getPackage_();
req.nonceStr = weChatBean.getData().getNoncestr();
req.timeStamp = weChatBean.getData().getTimestamp();
req.sign = weChatBean.getData().getSign();
Constant.PAY_FROM = 1;
api.sendReq(req);
} else {
mPayCallBack.onResponse(-1);
}
}
public void onResponse(int code) {
mPayCallBack.onResponse(code);
}
}
複製代碼
使用接口統一回調;
public interface PayCallBack {
// code: 0爲失敗,-1爲失敗,-2爲取消
//經過code統一刷新界面
void onResponse(int code);
}
複製代碼
switch (msg.what) {
case AliPayWay.SDK_PAY_FLAG: {
PayResult payResult = new PayResult((String) msg.obj);
// 支付寶返回這次支付結果及加簽,建議對支付寶簽名信息拿簽約時支付寶提供的公鑰作驗籤
String resultStatus = payResult.getResultStatus();
// 判斷resultStatus 爲「9000」則表明支付成功,具體狀態碼錶明含義可參考接口文檔
if (TextUtils.equals(resultStatus, "9000")) {
mPayCallBack.onResponse(0);
} else {
// 判斷resultStatus 爲非「9000」則表明可能支付失敗
// 「8000」表明支付結果由於支付渠道緣由或者系統緣由還在等待支付結果確認,最終交易是否成功以服務端異步通知爲準(小几率狀態)
if (TextUtils.equals(resultStatus, "8000")) {
Toast.makeText(mActivity, "支付結果確認中", Toast.LENGTH_SHORT).show();
} else if (TextUtils.equals(resultStatus, "6001")) {
mPayCallBack.onResponse(-2);
} else {
// 其餘值就能夠判斷爲支付失敗,包括用戶主動取消支付,或者系統返回的錯誤
mPayCallBack.onResponse(-1);
}
}
break;
}
case AliPayWay.SDK_CHECK_FLAG: {
Toast.makeText(BaseApplication.getContext(), "檢查結果爲:" + msg.obj, Toast.LENGTH_SHORT).show();
break;
}
default:
break;
}
複製代碼
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WeChatWay.getInstance(Constant.APP_ID).getApi().handleIntent(getIntent(),this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
WeChatWay.getInstance(Constant.APP_ID).getApi().handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
}
/**
* 4、接收支付返回結果
*/
@Override
public void onResp(BaseResp resp) {
WeChatWay.getInstance(Constant.APP_ID).onResponse(resp.errCode);
}
}
複製代碼
將服務端返回的數據解析成預先定義好的AlipayBean,而後調起支付
RxSubscriber rxSubscriber = new RxSubscriber(this, new Callback<WeChatBean>() {
@Override
public void onNext(WeChatBean weChatBean) {
if (weChatBean.getCode().equals("waitpay")) {
//調起微信支付
WeChatWay weChatWay = WeChatWay.getInstance(Constant.APP_ID);
weChatWay.startPay(OrderDetailActivity.this, weChatBean, new PayCallBack() {
@Override
public void onResponse(int code) {
refreshDataWithCode(code);
}
});
} else {
CommonUtils.showToast(mContext, weChatBean.getMessage());
}
}
});
RequestManager.getInstance().sendRequest(weChatBeanObservable, rxSubscriber);
複製代碼
Observable<WeChatBean> weChatBeanObservable = RxRequest.getInstance().getProxy(false).callWeChatPay(map);
RxSubscriber rxSubscriber = new RxSubscriber(this, new Callback<WeChatBean>() {
@Override
public void onNext(WeChatBean weChatBean) {
if (weChatBean.getCode().equals("waitpay")) {
//調起微信支付
WeChatWay weChatWay = WeChatWay.getInstance(Constant.APP_ID);
weChatWay.startPay(OrderDetailActivity.this, weChatBean, new PayCallBack() {
@Override
public void onResponse(int code) {
refreshDataWithCode(code);
}
});
} else {
CommonUtils.showToast(mContext, weChatBean.getMessage());
}
}
});
RequestManager.getInstance().sendRequest(weChatBeanObservable, rxSubscriber);
複製代碼