Github博文地址,此處更新可能不是很及時。
好久沒寫博客了,好大一個坑。正好,最近剛做完應用市場的高速下載功能,便拿來填了這個坑。
話說產品為了增加用戶量,提升用戶活躍度以及配合推廣,更坑爹的是看到其他市場也有這些功能,等等,要求做一個捆綁下載的功能。WTF。
當然吐槽歸吐槽,任務還是要完成的。
具體要求是: 用戶在手機瀏覽WAP站點的時候,1.進入應用詳情頁時打開本應用(應用市場)里面的詳情頁面 2.點擊WAP端高速下載時,如果本應用已安裝,則調用本應用進行下載,否則下載本應用的捆綁包,安裝完成之后,在本應用打開時去下載之前用戶想下載的應用。 如何實現這兩個功能呢?以下逐步分析:
1.功能需求
如之前所描述。
一般來說,完成之前的兩個功能,一般都是需要應用已安裝並且在后台運行(最簡單的理解就是應用打開過應用,並且沒有被其他程序殺死),因此此處也默認這種情形才算應用已安裝;否則,一概認為是未安裝(以下沒有特別說明,均為這種情況)。
2.競品分析
當然,既然競品有了這些功能,那就先拿來主義,研究下他們是怎么做的吧。通過Chrome抓包分析,最后分析如下。
百度手機助手 http://127.0.0.1:6259/
搜狗手機助手 http://127.0.0.1:12388/
豌豆莢 自定義協議wandoujia://detail/app/cn.buding.martin
百度手機助手以及搜狗手機助手的方案基本是一致的,采用的是訪問一個手機本地服務地址127.0.0.1(回環地址),端口地址有所不同,豌豆莢采用的是自定義協議,后續讓瀏覽器自動幫它分發給注冊了wandoujia協議的Activity。
打開應用詳情 這個在打開瀏覽器相應詳情頁面時,百度手機助手以及搜狗手機助手同時訪問本地回環地址,而豌豆莢則調用自定義協議由系統調用相關的應用(一般就是豌豆莢)。
高速下載原理 豌豆莢沒有實現在應用已安裝情形下調用客戶端進行下載,在點擊下載時,詢問用是下載捆綁包還是直接下載想要下載的應用(描述文案見文末附圖,文案有誘導性)。選擇下載捆綁包,則下載一個特定文件名的豌豆莢安裝包。在安裝完成之后,去掃描特定的目錄(一般是download以及常見瀏覽器的下載目錄),如果存在符合規則的文件,則提取相關的資源ID,后續再下載捆綁的APP。
- 在應用沒有安裝的情形下。而百度手機與搜狗手機助手點擊高速下載(名字也有誘導),則直接下載一個APP,所有APP內容一樣,但是APP名字有所不同,均類似於app_捆綁id_xx.apk,比如搜狗手機助手捆綁微信的為MobileTools_8271386494777466339_71.apk,捆綁其他包的捆綁id有所不同。其他流程同豌豆莢。如果存在多個符合條件的apk,搜狗手機助手則取最新的信息進行下載,百度手機助手沒有研究。
- 如果手機APP已經安裝。豌豆莢沒有實現,而百度手機助手以及搜狗手機助手,則是瀏覽器網頁直接請求一個回環地址(127.0.0.1:port/actionpath?parameter),port為端口地址,百度手機助手為6259,搜狗手機助手為12388。actionpath為需要進行的操作,不同的操作,值也不一致 parameter為相關操作的參數,在這里把需要捆綁下載的APP數據傳過去。手機APP通過應用內的HTTP服務器接收到相關數據后進行應用下載,同時返回相應的數據。
3.最后方案
調起詳情頁面,采用HTTP服務器以及自定義協議兩種都可以,而且自定義協議不用一直在后台跑一個承載HTTP服務器的Service,會比較省電。
后續的高速下載,豌豆莢是沒有了,既然之前說到自定義協議省電,能否考慮呢?再結合需求,看下,應用未安裝的情形下,直接下載捆綁包,兩種都沒有問題;應用已安裝的情形,調起客戶端進行下載。自定義協議可以做到么?如何知道應用是否安裝了呢?瀏覽器有相應的API么?顯然沒有,就算有,也只可能部分有,但是要支持所有的瀏覽器。唯一的辦法就是通過訪問HTTP服務器,同時設置超時時間,一定時候內沒有響應則認為應用未安裝,下載相應的捆綁包。而且,通過HTTP服務器后續擴展也好,可以通過網頁服務器與Web進行雙向互動,比如百度手機助手可以通過web獲得位置信息。而自定義協議就顯然做不到這些。當然除了省電。
高速下載的調起解決了,那如果應用沒有安裝,在本應用安裝完成之后,如何知道之前用戶需要下載的是哪個應用呢?也就是捆綁應用的識別。 應用市場最開始的方案是在應用里面(asset文件夾下)打入一個文件,存放有捆綁應用的id號。但是,針對少量應用可以(最開始為了測試捆綁效果時用過),目前來說,針對大量應用肯定不行,需要打大量的包,而且需要不少存儲空間。
參考競品的方案,確實很完美,但是,考慮目前大部分的手機安全或者清理軟件,都會在應用安裝成功后提示刪除安裝包,同時,瀏覽器的下載目錄可能會會變。那這里能掃描整個SD卡,去尋找符合條件的文件么?肯定不行,太消耗時間了。
那在應用沒有安裝或者沒有在后台運行的情形下,如何知道捆綁的應用id呢。以上兩個方案都不完美,如何解決。與后端彥飛探討過,在高速下載apk時,網頁記錄手機下載的捆綁app id以及packagename以及該設備的唯一id(uuid),然后在打開市場時,請求相應的接口並把uuid傳入,獲得數據,從而下載相應的應用。想法超贊,后來發現沒有實用價值,uuid暫時沒有一個合理的方案。關鍵在於兩端生成的都要唯一,mac,ip?如何生成?
后來吃飯與國暢探討后,考慮是不是可以調用本地代碼去執行相關任務?但仔細思考過后,發現這個一般是WebView與js進行交互。而目前的使用場景根本就無法做到。這個Webview必須要是自己應用內的才可以。
考慮多方面因素,最后決定,參考百度手機助手以及搜狗手機助手的方案,盡管有缺陷。 關於自定義協議模式,可參考此文章,android自定義協議和html加載時自動嘗試調用本地APP,以及Android 注冊監聽自定義協議,本文不做過多介紹。
最后的方案就是手機端后台通過Service運行一個HttpServer,監聽12307端口。
調起客戶端
1.高速下載
網頁端點擊高速下載時,訪問http://127.0.0.1:12307/appdown?downid=1&packagename=com.sogou.map
如果成功,返回json串形式為

1 { "status":1, "message":"OK" }
status為0表示失敗,status為1表示成功。message為具體描述。
如果在一定時間內手機沒有響應,則默認應用沒有安裝,下載捆綁APK包。
如果手機端響應了,則網頁端不做任何處理,手機端獲得相應的downid以及packagename,先判斷應用是否已經安裝,如果安裝,則提示應用已安裝,如果未安裝,則提示用戶應用正在下載,然后加入下載列表。
2.打開詳情頁面
http://127.0.0.1:12307/godetail?downid=1&packagename=com.sogou.map&backtohome=ture backtohome為true時,按下手機端的返回按鈕回到應用的主頁,為false時返回瀏覽器。(可參考豌豆莢,比如(http://www.wandoujia.com/apps/com.tencent.mm)[http://www.wandoujia.com/apps/com.tencent.mm]必須手機端訪問,User-Agent與PC訪問不同)
安裝包應用捆綁
如何識別捆綁的是哪個應用呢?
后續參考競品的實現方式,通過下載文件名不同(文件名有規則)的文件,在用戶安裝應用並且打開后去讀取下載文件夾,判斷是否存在符合規則的apk。如果存在,提取相應的id,去進行相應的下載。只要服務器提供接口讓瀏覽器在下載同一個文件顯示為不同的文件名即可。
比如搜狗手機助手的一個微信詳情地址為http://wap.sogou.com/app/apkdetail.jsp?ppid=34&cid=49&docid=8271386494777466339&e=1394,高速下載安裝包的地址是http://download.zhushou.sogou.com/zhushou/android/MobileTools.apk?dn=MobileTools_8271386494777466339_71.apk 下載下來的apk名稱為MobileTools_8271386494777466339_71.apk。捆綁的應用id為8271386494777466339,應用為微信。通過設置HTTP返回數據的headers的Content-Disposition字段為attachment;filename="MobileTools_8271386494777466339_71.apk"就可以實現,一般來說,主流瀏覽器都支持該屬性。
因此,最終確定,APK的命名方式為XXXX_binding_downid_9.apk,判斷應用為這種格式(可通過正則匹配)就會提取downid(downid必須為整數)。應用未安裝時,點擊高速下載,下載以上規則命名的apk到文件夾。用戶安裝應用並打開應用時,去掃描常用的下載文件夾(常見的/download,/downloads,以及瀏覽器下載文件夾等)里面的apk,有符合規則的則提取某一個文件中的id,提取完成之后,進行下載,同時把安裝包刪除(防止對之后進行干擾)。考慮到同一個文件夾可能有多個符合規則的安裝包,則按照時間順序取當前文件夾符合規則的時間最近的兩個,其他的文件夾的忽略,等下次啟動再處理(一般這種情況也比較少)。當然還有其他一些細節需要處理,此處不再詳談。
4.性能優化與展望
程序優化,是有追求的攻城師必須做的事情,因此,當然要優化嘍。
為了省電,指定了以下兩條策略。
1. 在網絡變化時,如果沒有網絡,則關閉服務,有網絡,則打開服務。解屏以及鎖屏時分別打開以及關閉服務。
2. 有網,且屏幕打開是觸發服務開啟的必要條件。可以大部分降低應用在鎖屏狀態下有網絡變化而導致的耗電問題。
以上兩個策略可疊加使用,可能會有些問題,比如有些時候條件都符合,但是服務沒有開啟(網絡十分頻繁的切換可能會導致)。
設定為以上條件是因為,后續的操作都是有網才能完成,其次,鎖屏狀態下,一般用戶是沒辦法觸發相關的流程的,除非程序自動觸發(即時通訊軟件接收信息比如,或者自動下載,但是這太流氓了)才需要在鎖屏時在后台跑。
HTTP服務器是用的Github上開源的Nanohttpd,http服務器除了高速下載,也可以用在,比如傳輸數據到電腦,應用與網頁交互等等很多方面。
5.最終實現
可訪問 http://app.sogou.com/m查看最終效果。
大致的思路就是以上描述。希望對大家有所啟發,起個拋磚引玉的作用。
目前暫時未上線,估計等到11月5號。
6.相關工具以及附錄
(1)Chrome 開發者工具+設備模式(數據抓包)
(2)三個市場的微信下載的演示地址:百度手機助手,搜狗手機助手,豌豆莢
當時(2014-10-27的頁面截圖如下)
(3)常見瀏覽器的APK下載路徑(#表示該行是注釋,每行一個目錄,目前不支持遍歷子目錄)

1 #this is the binding apk file path 2 #this is a comment 3 #some system default, Chrome, Opera, Opera mini, Sogou Broswer, ES File Explorer,Dolphin Browser 4 download 5 #meizu browser, some system default 6 download/apk 7 downloads 8 #uc browser 9 UCDownloads 10 #QQ Broswer 11 QQBrowser/安裝包 12 QQBrowser/下載 13 qqbrowser/download 14 #QQ Broswer HD 15 QQBrowser 16 #baidu broswer 17 baidu/flyflow/downloads 18 #baidu app 19 baidu/searchbox/downloads 20 #Maxthon Broswer 21 MxBrowser/Downloads 22 TTDownload/installapk 23 Application 24 ThunderDownload 25 #liebao broswer 26 kbrowser_fast/download/App 27 #360 Broswer 28 360Browser/download 29 #360 Express Broswer 30 360ExpressBrowser/download 31 #2345 broswer 32 Download/2345瀏覽器下載/安裝包 33 #hao123 34 hao123/down/apk 35 DolphinBrowserCN/download 36 UCDLFiles 37 QCDownload 38 LXDOWNLOAD/DOWNLOAD 39 apc/ApcBrowser/downloads 40 #YueDong Broswer,Ignore,The apk file name is changed by the broswer,the same with 4G Explorer(do not support header's Content-Disposition attribute) 41 #ydBrowser/download 42 #4G-explorer/apks
哈哈哈哈,完美解決所有問題。之后還可以擴展。
本文來自RxRead's Blog,歡迎轉載,轉載請注明。