庫(kù)在何方肛著?
庫(kù)出何因圆兵?
現(xiàn)在市場(chǎng)上的各APP基本上都會(huì)集成微信、支付寶的支付了枢贿,好象不集成支付SDK讓用戶可以付付款就這家公司賺不到錢(qián)一樣殉农,呵呵!
如果公司就只有一個(gè)項(xiàng)目那么直接在項(xiàng)目的libs目錄下加入微信局荚、支付寶的支付SDK也就行了超凳,也只需要維護(hù)一套代碼愈污。然而如果有兩個(gè)以上的項(xiàng)目都需要集成支付的情況下,就需要在每個(gè)項(xiàng)目的libs目錄下都加入支付SDK并維護(hù)相應(yīng)的代碼轮傍,而代碼基本上相同暂雹,當(dāng)然使用寫(xiě)程序大法——Ctrl+C-->Ctrl+V,也可,但是如果微信创夜、支付寶的支付SDK更新改動(dòng)了呢杭跪?又需要回到每個(gè)項(xiàng)目下?lián)Q支付SDK、改代碼... 停驰吓、停涧尿、停,作為聰明程序員們可不能這么干檬贰,“偷懶”姑廉、代碼無(wú)限次重復(fù)利用,永遠(yuǎn)是寫(xiě)代碼的高等逼格與境界翁涤,程序員恨不得寫(xiě)一套代碼桥言,哪都能用!項(xiàng)目總是會(huì)越做越多葵礼,如果都要集成支付功能的話号阿,豈不累成狗。
于是本著偷懶的原則章咧,就很有必要把支付這種到處都相同的功能封裝起來(lái)形成哪哪都能用的庫(kù)項(xiàng)目倦西,讓APP開(kāi)發(fā)者只關(guān)心支付的結(jié)果,如果微信赁严、支付寶的SDK更新了扰柠,更新此庫(kù)就行,你繼續(xù)只關(guān)心支付的結(jié)果而已疼约,于是此庫(kù)就這樣被我碼出來(lái)了卤档,并且運(yùn)用到公司的項(xiàng)目中,筆者也會(huì)隨著微信程剥、支付寶支付SDK的更新而更新劝枣;
微信、支付寶支付那事
首先兩個(gè)支付平臺(tái)都不對(duì)個(gè)人提供服務(wù)了(以前能织鲸,想想那時(shí)一些個(gè)人通過(guò)這個(gè)東西舔腾,就能把錢(qián)付到個(gè)人的帳戶下哈,那酸爽...),現(xiàn)在都必須是商戶帳戶稳诚。
支付寶支付的集成沒(méi)什么好說(shuō)的,挺友好瀑踢,集成簡(jiǎn)單扳还。
可網(wǎng)上一搜微信支付那點(diǎn)事才避,說(shuō)得比較多的就是微信支付那些坑,記得剛開(kāi)始集成微信支付的時(shí)候氨距,直接去的官網(wǎng)看資料以及Demo桑逝,心想集成一個(gè)SDK還不簡(jiǎn)單,參考Demo來(lái)就是俏让±愣簦可真正要完整穩(wěn)當(dāng)?shù)倪\(yùn)行集成好的微信支付還是要費(fèi)點(diǎn)精力的,要不然也不會(huì)有那么多人抱怨微信支付的坑舆驶。
我也就舉兩個(gè)栗子:
1. 要想能發(fā)起微信支付橱健,必須去微信開(kāi)放平臺(tái)登陸商戶的帳號(hào),再為需要集成微信支付的APP建立檔案然后提交審核(這期間一言不合就政審不通過(guò)),再申請(qǐng)開(kāi)通支付能力吧沉(又是一言不合就政審不通過(guò)啊臼节!扒肆辍!巴臁>匏啊),過(guò)個(gè)一星期半月的等所有的都通過(guò)了粉臊,你才能真正使用微信支付了(嗯草添,開(kāi)始能從用戶那收錢(qián)了,我們程序員為這些個(gè)商戶想想都有點(diǎn)小激動(dòng)哈)扼仲。
好家伙远寸,就是要這么繁瑣、磨人屠凶!直接導(dǎo)致程序員在調(diào)用微信支付SDK的代碼行間注釋個(gè)//fuck the weixin!驰后,好嘛,支付能力也開(kāi)通了矗愧,SDK的代碼也寫(xiě)好了灶芝,一跑程序,正預(yù)想著大方的給微信資助個(gè)一毛五分的唉韭,什么鬼夜涕?!都還沒(méi)打開(kāi)微信的大門(mén)呢属愤,就被打回來(lái)了女器。(哈哈,又找到一個(gè)微信的BUG春塌,APP崩潰了不會(huì)吧晓避,嘿簇捍,別笑,我們的APP寫(xiě)得沒(méi)微信好G喂啊)暑塑,最后發(fā)現(xiàn),噢锅必,調(diào)個(gè)試事格,也需要給項(xiàng)目打個(gè)正式的包啊,再次說(shuō)出那世界通用口號(hào):“fuck搞隐!”驹愚,程序員本來(lái)挺單純,現(xiàn)在都能出口成章(臟)劣纲,是Bug Bi的逢捺、是環(huán)境Bi的,是有原因的癞季。劫瞳。。
2. 微信的SDK集成好了绷柒,代碼姿勢(shì)參考官方Demo也寫(xiě)正確了志于,也打正式包了,那就來(lái)說(shuō)說(shuō)微信支付的坑废睦。網(wǎng)上描述的那些坑伺绽,我倒是沒(méi)有踩到過(guò),不知道是不是自己人品問(wèn)題還是微信的SDK已經(jīng)修改好了嗜湃。
我就來(lái)說(shuō)說(shuō)一個(gè)沒(méi)多少人注意到的坑(微信支付團(tuán)隊(duì)果然NB奈应,坑都隱藏得這么好),手機(jī)內(nèi)安裝一個(gè)微信或者把之前微信的登陸帳號(hào)退出來(lái)净蚤,然后啟動(dòng)APP發(fā)起支付,這時(shí)調(diào)起微信支付钥组,微信會(huì)判斷沒(méi)有帳號(hào)登陸,則彈出登陸界面今瀑,就是這個(gè)界面程梦,微信有考慮用戶不去登陸啥也不做直接返回嗎?橘荠?這時(shí)用戶直接返回屿附,到我們自己的APP界面(一般為支付過(guò)渡界面,說(shuō)時(shí)尚點(diǎn)就是菊花一直轉(zhuǎn)等待響應(yīng)結(jié)果的界面),程序員會(huì)發(fā)現(xiàn)哥童,微信支付SDK什么也不返回挺份!本應(yīng)該返回支付結(jié)果的代碼見(jiàn):
public void onResp(BaseResp resp) {
//....你倒是給老子響應(yīng)啊
}
就這樣,說(shuō)好的支付響應(yīng)結(jié)果再也不見(jiàn),讓別人的APP里一直轉(zhuǎn)的菊花情何以堪V浮匀泊?讓用戶一直看著菊花轉(zhuǎn)那心理多煎熬优训!
不過(guò)后來(lái),大概2016-10-1國(guó)慶節(jié)前各聘,微信APP升級(jí)了一把(截至2016-11-03揣非,微信的版本為:6.3.28),這個(gè)坑被填好了,不過(guò)從多年開(kāi)發(fā)經(jīng)驗(yàn)以及善于測(cè)試的筆者來(lái)看躲因,放心吧早敬,還會(huì)有坑的!
總結(jié)一下微信大脉、支付寶支付SDK
微信支付SDK就像一個(gè)矯情的小娘們一樣搞监,而支付寶支付SDK像個(gè)糙男實(shí)用男,隨便你怎么用怎么玩镰矿,隨便一個(gè)APP把它的SDK一集成就能付錢(qián)琐驴,只認(rèn)錢(qián)不認(rèn)APP。
本庫(kù)的使用方法
上面扯了那么多秤标,都不是重點(diǎn)棍矛,只是發(fā)一發(fā)程序員的牢騷,還是那句話抛杨,本庫(kù)只讓使用者只關(guān)心微信、支付寶支付的支付結(jié)果荐类,一切有的坑都讓本庫(kù)承擔(dān)怖现。
這里才是重點(diǎn),依賴(lài)本庫(kù)玉罐,簡(jiǎn)單幾步屈嗤,就可以發(fā)起支付,正確姿勢(shì)如下吊输,
1:本項(xiàng)目為Android的庫(kù)工程饶号,首先要讓需要集成支付功能的APP項(xiàng)目依賴(lài)本庫(kù),我們都是有Android程序員身份的人季蚂,相信大家都會(huì)茫船,后續(xù)把本庫(kù)發(fā)布到jitpack上去,讓使用者能進(jìn)行g(shù)radle依賴(lài)扭屁。
2:依賴(lài)本庫(kù)成功后,在自己APP項(xiàng)目里需要發(fā)起微信或者支付寶支付的地方調(diào)用本庫(kù)的方法即可坐等支付結(jié)果算谈,當(dāng)然我們先來(lái)熟悉一遍整個(gè)支付流程。
發(fā)起支付的流程(2017-01-05有更改):
1). 首先APP的訂單界面提供用戶選擇使用微信還是支付寶支付方式料滥,這樣好讓APP的后臺(tái)服務(wù)端給返回對(duì)應(yīng)的訂單信息然眼。微信的訂單信息如下(參考別人公司的):
{
"status": "1",
"msg": "請(qǐng)求成功",
"data": {"orderNo": "551515515151551",
"appid": "wxbee9e8888665656",
"partnerid": "01234598565",
"prepayid": "wx20160122151438e832d724940443134124",
"noncestr": "uphct75fl9qexvpeeiy8k0cdzo13h7ap",
"timestamp": "1453446877",
"package": "Sign=WXPay",
"paySign": "1C71DBC9F32B41723165554987DD0F7"
}
對(duì)應(yīng)于發(fā)起微信的支付,微信又矯情了一下葵腹,它需要相應(yīng)的請(qǐng)求對(duì)象高每,見(jiàn):
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中需要什么字段信息屿岂,我們的服務(wù)端就必須返回相應(yīng)的字段信息。
而對(duì)于支付寶支付服務(wù)端返回的訂單信息(參考別人公司的)示例如下:
{
"status": "1",
"msg": "請(qǐng)求成功"鲸匿,
"data": {
"orderNo": "2016011310211365556",
"payInfo": "partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="測(cè)試"&body="測(cè)試測(cè)試"&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"
? ? ? ? ? ? ? ?}
}
支付寶的支付訂單請(qǐng)求數(shù)據(jù)就是一字符串爷怀,參考官方的請(qǐng)求示例,總之就是說(shuō)晒骇,APP能返回對(duì)應(yīng)的滿足微信或者支付寶的訂單信息就行霉撵,而我們一般會(huì)把服務(wù)端的響應(yīng)給解析成對(duì)應(yīng)的Java實(shí)體對(duì)象,本庫(kù)也不例外洪囤,當(dāng)然各公司的后臺(tái)服務(wù)端返回的數(shù)據(jù)不一定如上面所示的Json數(shù)據(jù)格式徒坡。
所以本庫(kù)為了兼容各自公司不同的返回?cái)?shù)據(jù),所以本庫(kù)把微信支付請(qǐng)求數(shù)據(jù)以及支付寶支付請(qǐng)求數(shù)據(jù)提升為接口形式ICanPayOrderInfo瘤缩,
只要你所解析成的實(shí)體對(duì)象實(shí)現(xiàn)本庫(kù)的接口ICanPayOrderInfo喇完,就完成了使用本庫(kù)發(fā)起支付的決定性條件。
2). 發(fā)起支付剥啤,只需一行代碼锦溪,調(diào)用方式一(該方法已被聲明為過(guò)時(shí)):
PayEntryActivity.startPayActivity(Activity activity,ICanPayOrderInfo curPrePayOrderInfo, intrequestCode);
其中第一個(gè)參數(shù),它認(rèn)識(shí)你府怯,你也認(rèn)識(shí)它刻诊,無(wú)需多說(shuō),第二個(gè)參數(shù)即為上面實(shí)現(xiàn)了ICanPayOrderInfo的支付訂單請(qǐng)求信息對(duì)象,第三個(gè)參數(shù)為啟動(dòng)一個(gè)Activity并需要返回結(jié)果時(shí)的請(qǐng)求碼牺丙,用來(lái)區(qū)分回到調(diào)用界面時(shí)则涯,是由本庫(kù)的支付界面所返回的情況。
上面的調(diào)用方式一目前只適合發(fā)起阿里的支付寶支付冲簿,因?yàn)槲⑿胖Ц禨DK對(duì)接收支付結(jié)果響應(yīng)的Activity限制得非常死粟判,所以要發(fā)起微信支付時(shí)如果調(diào)用該方法,將不能成功得到支付結(jié)果峦剔,改用調(diào)用方式二:
PayEntryActivity.startPayActivity(Activity startActivity,ICanPayOrderInfo curPrePayOrderInfo, intrequestCode,Class<? extendsPayEntryActivity> localWxPayEntryActivityClass);
方式二則為完全通用支付寶支付/微信支付的方法档礁,相比方式一,多了一個(gè)參數(shù)Class localWxPayEntryActivityClass吝沫,該參數(shù)就是為了解決微信支付SDK對(duì)接收支付結(jié)果Activity的包路徑限制的作用呻澜,這不得不吐草一下,微信支付SDK對(duì)接收支付響應(yīng)的Activity的名稱(chēng)一定要為【W(wǎng)xPayEntryActivity】野舶,而且該Activity一定要在【wxapi】包下易迹,而且【wxapi】包一定要在你的APP的包名(該包名也為在微信支付開(kāi)放平臺(tái)上寫(xiě)明的包名)下,具體示例為:
微信支付SDK這樣限制其實(shí)對(duì)有多渠道打包需求來(lái)說(shuō)非常不方便(如果各位大神有好的解決方案平道,歡迎不吝賜教)睹欲。
那么使用方式二時(shí),在你自己的APP的wxapi目錄下只需要寫(xiě)一個(gè)【W(wǎng)xPayEntryActivity】名字的類(lèi)來(lái)繼承本庫(kù)的【PayEntryActivity】即可,里面可以不寫(xiě)任何一行代碼,例如:
注:別忘記了在你的AndroidMenifest文件中注冊(cè)【W(wǎng)xPayEntryActivity】
當(dāng)然也可以在WxPayEntryActivity中來(lái)重寫(xiě)父類(lèi)【PayEntryActivity】中的一些方法來(lái)定制化一些內(nèi)容(比如跳轉(zhuǎn)到WxPayEntryActivity界面時(shí)更換掉默認(rèn)的布局窘疮,可重寫(xiě)PayEntryActivity的getProvideContentViewResID()方法等)袋哼。
最后方式二的調(diào)用則為:
PayEntryActivity.startPayActivity(Activity startActivity,ICanPayOrderInfo curPrePayOrderInfo, intrequestCode,WxPayEntryActivity.class);
OK,現(xiàn)在程序小哥你可以闸衫,抖個(gè)小腿涛贯,喝杯
,坐等支付結(jié)果蔚出。
3). 本庫(kù)響應(yīng)支付結(jié)果弟翘,您只需要在您的調(diào)用界面Activity的onActivityResult(){}方法中來(lái)處理響應(yīng)結(jié)果,見(jiàn)下:
private static final int TEST_REQUEST_PAY_CODE = 100;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//在該方法中骄酗,接收支付結(jié)果
//參考
switch (requestCode) {
case TEST_REQUEST_PAY_CODE:
String toastHint = "支付模式:%s,響應(yīng)碼:%s,結(jié)果描述:%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;
}
}
關(guān)于響應(yīng)支付結(jié)果的提示
微信和支付寶的官方都有提示到稀余,即使支付功能的SDK返回了支付成功,也不能完全代表本次支付流程真正成功了趋翻,而是各APP根據(jù)需要再去服務(wù)端查詢(xún)一遍本次的支付結(jié)果睛琳,以服務(wù)端的返回為準(zhǔn)!現(xiàn)在本地的支付結(jié)果已經(jīng)返回給你了踏烙,接下來(lái)的事师骗,各自為策吧,但作者的建議是讨惩,去查個(gè)毛線辟癌,如果要去服務(wù)端查一遍才能斷定是否真正支付成功,那微信/支付寶支付后返回的結(jié)果有個(gè)毛意義荐捻,不管失敗還是成功都去查一遍咯愿待?就算本地返回支付成功而實(shí)際上服務(wù)端可能是支付失敗,這個(gè)鍋?zhàn)孊AT背吧靴患,哦,不好意思這里沒(méi)B什么事要出。
目前本庫(kù)中微信鸳君、支付寶支付SDK的版本
這里說(shuō)的版本信息為官方所發(fā)布的SDK,即xx.jar的版本,見(jiàn)下患蹂,
支付寶支付SDK:
alipaySdk-20161009.jar
微信支付SDK:
本庫(kù)使用的是
libammsdk.jar (3.1.1)或颊,嗯,很久沒(méi)更新了传于,說(shuō)明鵝廠太忙了囱挑,忙的都快忘了...
光去微信下載個(gè)SDK都比較坑,進(jìn)入到下載界面
點(diǎn)擊這兩個(gè)下載沼溜,下載下來(lái)你會(huì)發(fā)現(xiàn)那個(gè)范例代碼里的微信支付的SDK jar文件還仍然是2012年的平挑,所以還是下載Android開(kāi)發(fā)工具包那個(gè)才是最新的,即為本庫(kù)所使用的,不過(guò)也是2015年的通熄。