微信、支付寶個人收款的一種實現思路
一、基本思路
這個方案的基本思路是非常簡單的,跟之前大家常用的用爬蟲爬取網頁賬單資料類似,但是這裡我們用的是手機App。相對來說,擷取手機App的推送訊息更為簡單,不需要應為微信支付寶的各種反爬措施;但是缺點是能夠獲取到的資訊較少,沒有諸如流水號、付款人之類的資訊,只有一個金額。
所以,我們的思路就是:
- 建立一個訂單,將二維碼(定額或者非定額都可以)展示給使用者
- 使用者支付後,商家手機App上收到支付寶的付款推送
- 安卓App擷取支付寶的付款推送,然後將付款資訊傳送給伺服器
- 伺服器根據付款金額,確定到底是哪一筆訂單,然後將該訂單標記為“已付款”,然後根據需要進行回撥通知之類的操作。
二、關鍵問題及其解決方案
這個方案裡的關鍵問題有以下幾個:
1.支付寶App的通知擷取
這個問題其實網上已經有很多的解決方案了,其利用的是Android中的NotificationListenerService
這個類,通過註冊這個Listener,可以在推送通知彈出來的時候,獲取到其傳送的App、標題、內容等資訊。我們最關心的就是App和推送內容。
判斷髮送App的包為支付寶的包,然後再從推送的內容中獲取到具體的內容,即可得到付款金額。
示例程式碼如下:
public class AlipayNotificationListenerService extends NotificationListenerService { public AlipayNotificationListenerService() { } @Override public void onNotificationPosted(StatusBarNotification sbn) { // 這裡可以拿到包名,可以按照需要判斷。 String packageName = sbn.getPackageName(); Notification notification = sbn.getNotification(); if (notification == null) { return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Log.e("SevenNLS","in 1"); Bundle extras = notification.extras; if (extras != null) { // 這裡是具體的title和content,可以從中提取金額 String title = extras.getString(Notification.EXTRA_TITLE, ""); String content = extras.getString(Notification.EXTRA_TEXT, ""); Log.d("Zachary", "title:" + title + " content:" + content); } } } @Override public void onListenerConnected() { Log.e("Zachary","connected"); } }
當然,為了讓這個App能夠順利進行,還要給它獲取通知的許可權,保證它不被清理等等,需要做一些相應的保護措施。
2.訂單的確定
剛才我們說過,伺服器收到App發來的收款資訊之後,還需要找到對應的訂單。這一步是相對比較難的一步,因為我們知道相同金額的訂單可能有很多,到底哪一個才是剛剛支付的訂單呢?
這裡,我們可以再詳細思考一下,其實這個訂單不僅僅是由這個金額確定的,而是一個多元組共同確定的。最簡單的一種實現方式就是 (訂單金額-支付狀態)。通過這個二元組可以確定一個訂單。其含義是,如果這個訂單已經支付過了,那麼我在查詢訂單的時候,就可以不用理會它了,我只需要查詢(指定金額-未支付)的訂單就可以了。
這樣可以基本解決這個問題。但是,我們考慮到除了正常支付外,還有可能會有另外一些情況。比如使用者建立了訂單之後,突然不想支付了,沒有進行接下來的操作。或者說,有人惡意在網站上建立了大量的訂單並且不支付。 這樣的後果是,這些訂單的狀態永遠都是未支付
為了應對這種情況,我們想到其實很多的支付都是有時間限制的,也就是說,訂單是有有效期的,一旦過了有效期,訂單就不能被支付了。所以我們也可以給訂單加一個有效時間的限制,比如5分鐘,一旦五分鐘內沒有被支付,就認為這個訂單已經失效了。這時,訂單的確定方式就變成了一個三元組(訂單金額-支付狀態-是否過期)。查詢的時候,只需要查詢(指定金額-未支付-未過期)的訂單就可以了。也就是說,任意一個訂單,最多隻會佔用這個金額5分鐘,一旦超過五分鐘,不管支付與否,你都可以繼續建立相同金額的訂單了。
但是這樣我們還是覺得不滿意,特別是對於某些支付金額相對單一的情況,可能每次都需要建立相同金額的訂單,這樣的話,再最壞情況下我們只能每隔五分鐘處理一個訂單,這個效率可以說是非常低效了。
在這裡,我們提出了一種trade-off的解決方法。一般的正常支付是不會使用這種方式的,也難以接受,但是對於我們來說,為了避免企業資質的認證和手續費,在一定程度上是可以接受的。
這種方式就是,當目前系統中已經有了某一金額的訂單的時候,如果我們要繼續建立相同金額的訂單,那麼我們就在指定金額上進行上下浮動,比如下浮一分錢,這樣金額就可以和之前的訂單區分開來,避免出現不能同時支付的情況。這樣,雖然我們在高併發情況下可能會有一定的損失(同時支付的人越多,差距越大),但是滿足了我們的高併發要求。
友情提示:如果金額發生浮動,可以告訴使用者這是隨機立減,一定程度上可以避免定價和實際支付金額的差距帶來的問題。(這種情況下就只能下浮,不能上浮,不然就變成隨機立加了)。
三、總結
總體上來說,我認為這種方案對於普通的個人使用者來說,是一種可以接受的方案。其優缺點總結如下:
優點:
- 不需要企業資質
- 沒有手續費
- 不對支付寶進行任何操作,沒有被支付寶進行風控的風險
缺點:
- 需要有一部手機一直執行,且要求網路條件良好,否則會丟失支付資料(可以有人工解決方案)
- 高併發時,訂單金額會產生浮動
- 如果金額浮動策略不合理,並且被人探索出規律,可能造成財產損失!!(例如短時間內建立大量訂單,這樣訂單價格會不斷下降,需要針對這種情況做出防範)