PhoneGap應(yīng)用開發(fā)的那些坑爹事兒
去年這個(gè)時(shí)候我很煩惱,因?yàn)槲矣X得我OUT了。
起因是我買了一臺(tái)Android系統(tǒng)的手機(jī)。當(dāng)我用自己的google賬號(hào)登錄上去后,我發(fā)現(xiàn)通訊錄被同步了,Gtalk實(shí)時(shí)通知了,Gmail隨身能看了。還有成百數(shù)千的應(yīng)用,讓我足足玩了一周。
電腦占據(jù)了用戶每天8小時(shí)的時(shí)間,網(wǎng)站創(chuàng)造了巨大的價(jià)值。但是,手機(jī)這東西卻能夠24小時(shí)不間斷的陪著用戶,消息推送機(jī)制更是讓用戶變得永久在線,隨時(shí)可響應(yīng)。我很興奮,但是卻高興不起來(lái)。
我是一個(gè)Web程序員。我喜歡寫PHP,喜歡處理Mysql,我能用CSS和JavaScript構(gòu)建不錯(cuò)的頁(yè)面。但是我不喜歡Java,也不喜歡寫Object C,就像那幫做客戶端開發(fā)的同學(xué)不喜歡寫網(wǎng)站后臺(tái)一樣。
這樣的沮喪持續(xù)了挺久,直到我遇到了PhoneGap。其實(shí)我有想過(guò)通過(guò)Mobile Web的方式進(jìn)入移動(dòng)互聯(lián)網(wǎng),但是在手機(jī)上輸入網(wǎng)址的體驗(yàn)太折磨了。另外消息推送和本地設(shè)備接口(比如攝像頭)都是問(wèn)題。而PhoneGap解決了這一切。簡(jiǎn)單的說(shuō),它就是一個(gè)提供js接口調(diào)用本地設(shè)備接口的瀏覽器,這個(gè)瀏覽器還可以打包成一個(gè)單獨(dú)的應(yīng)用,安裝到系統(tǒng),添加到桌面和發(fā)布到應(yīng)用市場(chǎng)。
由于完全基于瀏覽器,PhoneGap還有一個(gè)好處,可以很輕松的跨多個(gè)平臺(tái)。
基于PhoneGap,我用3天的時(shí)間,給TeamToy寫了一個(gè)手機(jī)客戶端,可以讀取工作組的通訊錄,可以瀏覽Feed和發(fā)布廣播。當(dāng)然,還能收通知。
雖然算只跳舞的熊,但它的確能工作。這讓我不禁想,這東西到底能做什么程度的應(yīng)用?
PhoneGap只是一個(gè)殼,它是不管里邊跑的應(yīng)用長(zhǎng)什么樣子的,更不會(huì)有那些移動(dòng)設(shè)備上常用的控件。
好在有其他的項(xiàng)目提供支持,其中最有名的是兩個(gè)。一個(gè)是sencha touch,一個(gè)jquery mobile。
于是我都試用了下,然后我明白了苦頭在后邊⋯⋯
當(dāng)時(shí)這些項(xiàng)目都還屬于發(fā)展期,連文檔都沒什么,需要自己去讀DEMO和源代碼。
首先我嘗試著用sencha touch寫了一個(gè)微盤的第三方客戶端。坦白的說(shuō),sencha touch表現(xiàn)不錯(cuò),在菜單導(dǎo)航和列表拖拽上都明顯比Jquery Mobile靠譜。但是sencha touch采用JS來(lái)描述整個(gè)page的結(jié)構(gòu),這讓你的layout看起來(lái)就像一堆json數(shù)據(jù)。
我很討厭這樣,因?yàn)檫@種級(jí)別的可讀性讓項(xiàng)目很難維護(hù)。另外,sencha1版本Bug也不少,比如那個(gè)List最后一行能拖拽出來(lái),卻永遠(yuǎn)點(diǎn)不到的問(wèn)題?,F(xiàn)在sencha已經(jīng)在測(cè)試2版本了,據(jù)說(shuō)提供了直接打包成本地應(yīng)用的工具,這樣也許就不需要PhoneGap了。

由于對(duì)Sencha Touch的編碼方式不認(rèn)同,我完全轉(zhuǎn)向了Jquery Mobile。JQuery Mobile的方式更容易接受,它完全使用HTML標(biāo)簽進(jìn)行頁(yè)面布局,你只需要通過(guò)data-role之類的標(biāo)簽來(lái)告訴JQM你想干什么就OK了。我用JQM寫了Riki.co的移動(dòng)版,有興趣的同學(xué)可以去體驗(yàn)下:http://riki.co/m/ (這個(gè)東西有很多問(wèn)題,下邊我會(huì)提到)
JQM最近已經(jīng)1.0了,成熟了不少,但是問(wèn)題依然很多。首先是底導(dǎo)航浮動(dòng)的問(wèn)題。JQM的底導(dǎo)航實(shí)現(xiàn)很詭異,丫是一個(gè)浮動(dòng)圖層,根據(jù)當(dāng)前屏幕的高度,把自己降到屏幕最下方,當(dāng)你拖動(dòng)頁(yè)面內(nèi)容時(shí),這個(gè)浮動(dòng)條還會(huì)隱藏。這個(gè)效果有多么的BT,真是誰(shuí)用誰(shuí)知道。沒用過(guò)的同學(xué)可以到這里去體驗(yàn)下官方版本: http://jqmdoc.sinaapp.com/docs/toolbars/footer-persist-a.html
這其實(shí)還不是最難受的,最難受的是,當(dāng)你把JQM打包到PhoneGap里邊后,由于未知原因10次里邊JQM能有2~3次取不到瀏覽器高度,直接造成導(dǎo)航掛掉。
這個(gè)問(wèn)題其實(shí)iScroll4 很好的解決了,它使用了相對(duì)距離的CSS來(lái)固定頂導(dǎo)航和底導(dǎo)航。所以后來(lái)我把它給整合到JQM里邊,然后天下太平了。
iScroll4還實(shí)現(xiàn)了列表拖拽刷新的功能,可以做出iPhone上常用的下拉刷新。

然后是頁(yè)面切換的問(wèn)題。JQM和Sencha其實(shí)都有,就是在android系列機(jī)器上,頁(yè)面切換時(shí)的抖動(dòng)和閃爍。最開始你注意到的時(shí)候,是切換的瞬間頁(yè)面反白一下,這個(gè)問(wèn)題其實(shí)可以解決,用一行CSS就可以了:
- .ui-page
- {
- -webkit-backface-visibility: hidden;
- }
但是,代價(jià)是慘重的。首先是會(huì)導(dǎo)致性能降低,然后是,當(dāng)你切到從頁(yè)面A切換到頁(yè)面B時(shí),頁(yè)面A的內(nèi)容會(huì)突然在滑動(dòng)效果結(jié)束后,再閃一下。親,這是坑爹啊還是坑爹啊。還沒完,如果你用的JQM,然后在android系統(tǒng)上用百度或者QQ輸入法,那么恭喜,當(dāng)你在輸入文字時(shí),頁(yè)面會(huì)上下不停的抖動(dòng),就像ZF要強(qiáng)拆它家似的。
JQM通過(guò)Ajax載入的頁(yè)面都有這個(gè)問(wèn)題,你可以選擇關(guān)閉Ajax載入,這樣每個(gè)頁(yè)面都獨(dú)立載入,除了速度慢點(diǎn)外,不能忍受的是列表滾動(dòng)條進(jìn)度會(huì)丟失。這意味著你在列表中部選中的一條內(nèi)容,查看完后,返回列表時(shí),列表又回到第一條去了。
最后我選擇了采用DIV切換的方式。我會(huì)在一個(gè)頁(yè)面把所有要用的Page都載入進(jìn)來(lái),然后display:none;在需要使用的時(shí)候再顯示出來(lái)。這樣做的問(wèn)題是一次讀取了較多的內(nèi)容,會(huì)稍微多占點(diǎn)內(nèi)存,另外沒有動(dòng)態(tài)切換效果;但好處顯而易見:頁(yè)面之間的切換速度已經(jīng)接近原生應(yīng)用。
我想說(shuō)的是,JQM是個(gè)好框架,但它并不是完全為在PhoneGap里邊跑的HTML設(shè)計(jì)的。它需要考慮資源載入速度和流量的問(wèn)題,而PhoneGap這種應(yīng)用資源都放本地的;它在瀏覽器上可以不斷的刷新頁(yè)面,所以它不用考慮太多內(nèi)存管理和DOM回收的事情,而對(duì)PhoneGap里邊的應(yīng)用來(lái)講,這直接決定了應(yīng)用的穩(wěn)定性。
這些差異決定了一個(gè)專門為PhoneGap這種應(yīng)用設(shè)計(jì)一個(gè)框架是必要的。而目前沒有一個(gè)好的框架解決掉我提到的這些問(wèn)題,我們只能小心的繞過(guò)這些一個(gè)個(gè)的雷點(diǎn)。( 如果你愿意寫一個(gè)這樣的框架,我可以提供一個(gè)新浪的全職職位 :) )
雖然我吐了一肚子的苦水,但是最終結(jié)果是很不錯(cuò)的,我現(xiàn)在已經(jīng)能以天為單位開發(fā)一些社交和資訊類應(yīng)用了,而這些應(yīng)用可以直接運(yùn)行在iPhone,Android和芒果上。
更好的消息是你不用再被折騰一遍,因?yàn)槲矣袀€(gè)東西給你。
#p#
那就是我在歷經(jīng)折磨后,做出的一個(gè)叫做LazyMobile的應(yīng)用模板。
它其實(shí)就是一個(gè)已經(jīng)寫好的應(yīng)用,你可以直接修改它,添加自己的功能。它看起來(lái)是這個(gè)樣子的:

這東西基于JQM和iScroll。
首先它用iScroll4解決了底導(dǎo)航固定的問(wèn)題,在android和ios上都很完美,下拉刷新也是可以用的。
然后它通過(guò)Tab切換來(lái)載入其他頁(yè)面,效果接近原生應(yīng)用,但是不要在一個(gè)List里邊放太多的數(shù)據(jù),少放點(diǎn),動(dòng)態(tài)加載和實(shí)時(shí)回收item項(xiàng)。我已經(jīng)做了一個(gè)兩級(jí)導(dǎo)航,應(yīng)該夠用了,微博客戶端也就用到二級(jí)導(dǎo)航。
它用JQuery的ajax函數(shù)從服務(wù)器端讀取json格式數(shù)據(jù),然后用jquery.tmpl進(jìn)行渲染,目前這個(gè)地方會(huì)消耗不少CPU,但暫時(shí)沒有更好的辦法。
另外,它還用localStroage存儲(chǔ)了上次網(wǎng)絡(luò)請(qǐng)求回來(lái)的json數(shù)據(jù),這樣在網(wǎng)絡(luò)斷開時(shí),依然可以顯示內(nèi)容。
這個(gè)項(xiàng)目完全是一個(gè)副產(chǎn)品,所以我不保證會(huì)維護(hù)它。不過(guò)你已經(jīng)知道了它的大多數(shù)細(xì)節(jié),我相信Web程序員都能很好的使用它。項(xiàng)目地址:http://code.google.com/p/lazymobile/
原文:http://ftqq.com/2011/12/12/the-days-develop-apps-using-phonegap/
【編輯推薦】