庫在何方?
庫出何因?
現在市場上的各APP基本上都會集成微信、支付寶的支付了,好象不集成支付SDK讓用戶可以付付款就這家公司賺不到錢一樣,呵呵!
如果公司就只有一個項目那么直接在項目的libs目錄下加入微信、支付寶的支付SDK也就行了,也只需要維護一套代碼。然而如果有兩個以上的項目都需要集成支付的情況下,就需要在每個項目的libs目錄下都加入支付SDK并維護相應的代碼,而代碼基本上相同,當然使用寫程序大法——Ctrl+C-->Ctrl+V,也可,但是如果微信、支付寶的支付SDK更新改動了呢?又需要回到每個項目下換支付SDK、改代碼... 停、停、停,作為聰明程序員們可不能這么干,“偷懶”、代碼無限次重復利用,永遠是寫代碼的高等逼格與境界,程序員恨不得寫一套代碼,哪都能用!項目總是會越做越多,如果都要集成支付功能的話,豈不累成狗。
于是本著偷懶的原則,就很有必要把支付這種到處都相同的功能封裝起來形成哪哪都能用的庫項目,讓APP開發者只關心支付的結果,如果微信、支付寶的SDK更新了,更新此庫就行,你繼續只關心支付的結果而已,于是此庫就這樣被我碼出來了,并且運用到公司的項目中,筆者也會隨著微信、支付寶支付SDK的更新而更新;
微信、支付寶支付那事
首先兩個支付平臺都不對個人提供服務了(以前能,想想那時一些個人通過這個東西,就能把錢付到個人的帳戶下哈,那酸爽...),現在都必須是商戶帳戶。
支付寶支付的集成沒什么好說的,挺友好,集成簡單。
可網上一搜微信支付那點事,說得比較多的就是微信支付那些坑,記得剛開始集成微信支付的時候,直接去的官網看資料以及Demo,心想集成一個SDK還不簡單,參考Demo來就是。可真正要完整穩當的運行集成好的微信支付還是要費點精力的,要不然也不會有那么多人抱怨微信支付的坑。
我也就舉兩個栗子:
1. 要想能發起微信支付,必須去微信開放平臺登陸商戶的帳號,再為需要集成微信支付的APP建立檔案然后提交審核(這期間一言不合就政審不通過),再申請開通支付能力啊(又是一言不合就政審不通過啊!啊!啊!),過個一星期半月的等所有的都通過了,你才能真正使用微信支付了(嗯,開始能從用戶那收錢了,我們程序員為這些個商戶想想都有點小激動哈)。
好家伙,就是要這么繁瑣、磨人!直接導致程序員在調用微信支付SDK的代碼行間注釋個//fuck the weixin!,好嘛,支付能力也開通了,SDK的代碼也寫好了,一跑程序,正預想著大方的給微信資助個一毛五分的,什么鬼?!都還沒打開微信的大門呢,就被打回來了。(哈哈,又找到一個微信的BUG,APP崩潰了不會吧,嘿,別笑,我們的APP寫得沒微信好!),最后發現,噢,調個試,也需要給項目打個正式的包啊,再次說出那世界通用口號:“fuck!”,程序員本來挺單純,現在都能出口成章(臟),是Bug Bi的、是環境Bi的,是有原因的。。。
2. 微信的SDK集成好了,代碼姿勢參考官方Demo也寫正確了,也打正式包了,那就來說說微信支付的坑。網上描述的那些坑,我倒是沒有踩到過,不知道是不是自己人品問題還是微信的SDK已經修改好了。
我就來說說一個沒多少人注意到的坑(微信支付團隊果然NB,坑都隱藏得這么好),手機內安裝一個微信或者把之前微信的登陸帳號退出來,然后啟動APP發起支付,這時調起微信支付,微信會判斷沒有帳號登陸,則彈出登陸界面,就是這個界面,微信有考慮用戶不去登陸啥也不做直接返回嗎??這時用戶直接返回,到我們自己的APP界面(一般為支付過渡界面,說時尚點就是菊花一直轉等待響應結果的界面),程序員會發現,微信支付SDK什么也不返回!本應該返回支付結果的代碼見:
public void onResp(BaseResp resp) {
//....你倒是給老子響應啊
}
就這樣,說好的支付響應結果再也不見,讓別人的APP里一直轉的菊花情何以堪!?讓用戶一直看著菊花轉那心理多煎熬!
不過后來,大概2016-10-1國慶節前,微信APP升級了一把(截至2016-11-03,微信的版本為:6.3.28),這個坑被填好了,不過從多年開發經驗以及善于測試的筆者來看,放心吧,還會有坑的!
總結一下微信、支付寶支付SDK
微信支付SDK就像一個矯情的小娘們一樣,而支付寶支付SDK像個糙男實用男,隨便你怎么用怎么玩,隨便一個APP把它的SDK一集成就能付錢,只認錢不認APP。
本庫的使用方法
上面扯了那么多,都不是重點,只是發一發程序員的牢騷,還是那句話,本庫只讓使用者只關心微信、支付寶支付的支付結果,一切有的坑都讓本庫承擔。
這里才是重點,依賴本庫,簡單幾步,就可以發起支付,正確姿勢如下,
1:本項目為Android的庫工程,首先要讓需要集成支付功能的APP項目依賴本庫,我們都是有Android程序員身份的人,相信大家都會,后續把本庫發布到jitpack上去,讓使用者能進行gradle依賴。
2:依賴本庫成功后,在自己APP項目里需要發起微信或者支付寶支付的地方調用本庫的方法即可坐等支付結果,當然我們先來熟悉一遍整個支付流程。
發起支付的流程(2017-01-05有更改):
1). 首先APP的訂單界面提供用戶選擇使用微信還是支付寶支付方式,這樣好讓APP的后臺服務端給返回對應的訂單信息。微信的訂單信息如下(參考別人公司的):
{
"status": "1",
"msg": "請求成功",
"data": {"orderNo": "551515515151551",
"appid": "wxbee9e8888665656",
"partnerid": "01234598565",
"prepayid": "wx20160122151438e832d724940443134124",
"noncestr": "uphct75fl9qexvpeeiy8k0cdzo13h7ap",
"timestamp": "1453446877",
"package": "Sign=WXPay",
"paySign": "1C71DBC9F32B41723165554987DD0F7"
}
對應于發起微信的支付,微信又矯情了一下,它需要相應的請求對象,見:
PayReq request = new PayReq();
request.appId = "wxd930ea5d5a258f4f";
request.partnerId = "1900000109";
request.prepayId= "1101000000140415649af9fc314aa427",;
request.packageValue = "Sign=WXPay";
request.nonceStr= "1101000000140429eb40476f8896f4c9";
request.timeStamp= "1398746574";
request.sign= "7FFECB600D7157C5AA49810D2D8F28BC2811827B";
即微信支付SDK中需要什么字段信息,我們的服務端就必須返回相應的字段信息。
而對于支付寶支付服務端返回的訂單信息(參考別人公司的)示例如下:
{
"status": "1",
"msg": "請求成功",
"data": {
"orderNo": "2016011310211365556",
"payInfo": "partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="測試"&body="測試測試"&total_fee="0.01"?ify_url="http://notify.msp.hk/notify.htm"&service="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30m"&sign="lBBK%2F0w5LOajrMrji7DUgEqNjIhQbidR13GovA5r3TgIbNqv231yC1NksLdw%2Ba3JnfHXoXuet6XNNHtn7VE%2BeCoRO1O%2BR1KugLrQEZMtG5jmJIe2pbjm%2F3kb%2FuGkpG%2BwYQYI51%2BhA3YBbvZHVQBYveBqK%2Bh8mUyb7GM1HxWs9k4%3D"&sign_type="RSA"
? ? ? ? ? ? ? ?}
}
支付寶的支付訂單請求數據就是一字符串,參考官方的請求示例,總之就是說,APP能返回對應的滿足微信或者支付寶的訂單信息就行,而我們一般會把服務端的響應給解析成對應的Java實體對象,本庫也不例外,當然各公司的后臺服務端返回的數據不一定如上面所示的Json數據格式。
所以本庫為了兼容各自公司不同的返回數據,所以本庫把微信支付請求數據以及支付寶支付請求數據提升為接口形式ICanPayOrderInfo,
只要你所解析成的實體對象實現本庫的接口ICanPayOrderInfo,就完成了使用本庫發起支付的決定性條件。
2). 發起支付,只需一行代碼,調用方式一(該方法已被聲明為過時):
PayEntryActivity.startPayActivity(Activity activity,ICanPayOrderInfo curPrePayOrderInfo, intrequestCode);
其中第一個參數,它認識你,你也認識它,無需多說,第二個參數即為上面實現了ICanPayOrderInfo的支付訂單請求信息對象,第三個參數為啟動一個Activity并需要返回結果時的請求碼,用來區分回到調用界面時,是由本庫的支付界面所返回的情況。
上面的調用方式一目前只適合發起阿里的支付寶支付,因為微信支付SDK對接收支付結果響應的Activity限制得非常死,所以要發起微信支付時如果調用該方法,將不能成功得到支付結果,改用調用方式二:
PayEntryActivity.startPayActivity(Activity startActivity,ICanPayOrderInfo curPrePayOrderInfo, intrequestCode,Class<? extendsPayEntryActivity> localWxPayEntryActivityClass);
方式二則為完全通用支付寶支付/微信支付的方法,相比方式一,多了一個參數Class localWxPayEntryActivityClass,該參數就是為了解決微信支付SDK對接收支付結果Activity的包路徑限制的作用,這不得不吐草一下,微信支付SDK對接收支付響應的Activity的名稱一定要為【WxPayEntryActivity】,而且該Activity一定要在【wxapi】包下,而且【wxapi】包一定要在你的APP的包名(該包名也為在微信支付開放平臺上寫明的包名)下,具體示例為:
微信支付SDK這樣限制其實對有多渠道打包需求來說非常不方便(如果各位大神有好的解決方案,歡迎不吝賜教)。
那么使用方式二時,在你自己的APP的wxapi目錄下只需要寫一個【WxPayEntryActivity】名字的類來繼承本庫的【PayEntryActivity】即可,里面可以不寫任何一行代碼,例如:
注:別忘記了在你的AndroidMenifest文件中注冊【WxPayEntryActivity】
當然也可以在WxPayEntryActivity中來重寫父類【PayEntryActivity】中的一些方法來定制化一些內容(比如跳轉到WxPayEntryActivity界面時更換掉默認的布局,可重寫PayEntryActivity的getProvideContentViewResID()方法等)。
最后方式二的調用則為:
PayEntryActivity.startPayActivity(Activity startActivity,ICanPayOrderInfo curPrePayOrderInfo, intrequestCode,WxPayEntryActivity.class);
OK,現在程序小哥你可以,抖個小腿,喝杯
,坐等支付結果。
3). 本庫響應支付結果,您只需要在您的調用界面Activity的onActivityResult(){}方法中來處理響應結果,見下:
private static final int TEST_REQUEST_PAY_CODE = 100;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//在該方法中,接收支付結果
//參考
switch (requestCode) {
case TEST_REQUEST_PAY_CODE:
String toastHint = "支付模式:%s,響應碼:%s,結果描述:%s";
String payModeDesc = "未知";
String payRespCode = "unKnow";
if (data != null) {
int payMode = data.getIntExtra(CommonPayConfig.INTENT_KEY_CUR_PAY_MODE, CommonPayConfig.PAY_MODE_WX);
payModeDesc = payMode == CommonPayConfig.PAY_MODE_ALIPAY ? "[支付寶]" : "[微信]";
payRespCode = data.getStringExtra(CommonPayConfig.INTENT_KEY_REAL_PAY_RESULT_STATUS_CODE);
}
String resultDesc = "支付失敗";
switch (resultCode) {
case CommonPayConfig.REQ_PAY_RESULT_CODE_OK:
resultDesc = "支付成功";
break;
case CommonPayConfig.REQ_PAY_RESULT_CODE_CANCEL:
resultDesc = "支付被取消了";
break;
case CommonPayConfig.RQE_PAY_RESULT_CODE_NO_WX:
resultDesc = "支付失敗,未安裝微信APP";
break;
case CommonPayConfig.RQE_PAY_RESULT_CODE_ERROR:
resultDesc = "支付失敗,";
break;
}
toastShow(String.format(toastHint, payModeDesc, payRespCode, resultDesc));
break;
}
}
關于響應支付結果的提示
微信和支付寶的官方都有提示到,即使支付功能的SDK返回了支付成功,也不能完全代表本次支付流程真正成功了,而是各APP根據需要再去服務端查詢一遍本次的支付結果,以服務端的返回為準!現在本地的支付結果已經返回給你了,接下來的事,各自為策吧,但作者的建議是,去查個毛線,如果要去服務端查一遍才能斷定是否真正支付成功,那微信/支付寶支付后返回的結果有個毛意義,不管失敗還是成功都去查一遍咯?就算本地返回支付成功而實際上服務端可能是支付失敗,這個鍋讓BAT背吧,哦,不好意思這里沒B什么事。
目前本庫中微信、支付寶支付SDK的版本
這里說的版本信息為官方所發布的SDK,即xx.jar的版本,見下,
支付寶支付SDK:
alipaySdk-20161009.jar
微信支付SDK:
本庫使用的是
libammsdk.jar (3.1.1),嗯,很久沒更新了,說明鵝廠太忙了,忙的都快忘了...
光去微信下載個SDK都比較坑,進入到下載界面
點擊這兩個下載,下載下來你會發現那個范例代碼里的微信支付的SDK jar文件還仍然是2012年的,所以還是下載Android開發工具包那個才是最新的,即為本庫所使用的,不過也是2015年的。