与webview打交道中踩过的那些坑
隨著HTML5被越來越多的用到web APP的開發當中,webview這一個神器便日漸凸顯出重要地位。簡要的說,webview能夠在移動應用中開辟出一個窗口,在里面顯示html頁面,css以及js代碼也可以被解析執行,它使用的是我們熟悉的webkit內核。android和ios都有相應的API,所以寫一份代碼在多個平臺運行的能力就是以webview為基礎的。
今天我們要聊的不是如何使用webview,而是筆者本人作為一名前端工程師,在與客戶端開發人員通過webview打交道中遇到的種種神奇事件。
事情還得從去年說起,我還是一個小白實習生的時候。當經理知道有webview這個神器之后,遂下令讓android組和ios組削減工作內容,所有共同的界面均由web組提供。而web組當時處于“傳統軟件公司無前端”的局面,頁面相當臃腫,壓根不適于移動設備。于是乎,不明局勢的經理指揮一個不明真相的小白實習生,帶著還沒使利索的jQuery,開始了所謂的Hybrid App開發。一個凄慘的故事拉開序幕,下面是在開發當中踩過的各種坑,記錄下來以供備忘。
webview與設備自帶瀏覽器一樣嗎?
webview會調用系統自帶的瀏覽器內核來解析頁面。這是個真命題嗎?市場上的大部分平板電腦自帶瀏覽器為webkit內核,webview使用的也是webkit內核,并且按一個應用的大小來看也不可能自己帶一個內核進去。所以是調用系統自帶的是沒錯的了。那我在一臺設備上,使用瀏覽器打開一個頁面和使用webview打開同一頁面,得到的結果會是一模一樣嗎?當然是廢話了,都說了是調用關系。
假如真是廢話,那我也沒必要記下這一點了。因為從我的實際操作情況來看,有些時候確實是不一樣的。瀏覽器里一個樣,webview里又是一個樣。ipad上情況好些。在android品牌雜亂的設備上,此現象還真的出現不只一次。尤其是頁面DOM結構比較復雜的時候。
有理由懷疑我的代碼不符合W3C規范啥的,但業界良心,W3C規范還是不敢違反的。所以得出結論,webview與自帶瀏覽器解析的結果并不是完全一致,不能以為頁面在瀏覽器中正常了,在移動設備上也就正常了。
絕對要慎用的瀑布流
大概是兩年前,瀑布流這個概念紅遍大江南北,各網站紛紛效仿,相應的文章、jQuery插件層出不窮。后來真正有思想的人開始質疑,提出我們要學習的不是瀑布流的形式,而是思想,我們需要的是真正適合自己產品的東西。后來,我們經理也聽說了瀑布流這個東西。。。
加!加瀑布流!我們不要分頁列表那些東西!于是小白實習生網上各種搜索,找到了當時比較流行的叫做infinitescroll的jQuery插件。各種改源碼配合實現產品業務、各移動設備兼容性bug處理暫且放一邊。這里要提的是與移動應用密切相關的一個問題。
做移動開發的對閃退這種現象估計是咬牙切齒,移動應用的性能問題一直是不容小覷的。就webview來講,當html頁面的DOM元素很多,或者說層級關系較復雜時,對其的壓力是相當大的。再看看我們的瀑布流,隨著頁面的滾動,不斷往上append節點,這對webview來說壓力極大,當節點數量到一定程度時,就發現頁面滾動不是那么流暢,開始一卡一卡。別急,你在翻轉一下屏幕試試,瞬間崩潰,界面這個花了,內容像是繪制不出來一樣。因為在做橫豎屏翻轉時,解析引擎會進行頁面的重繪,這么多的節點工作量可不小。ipad因為其優越的圖像處理性能表現還不錯,android設備上簡直一塌糊涂。
有什么解決辦法呢?我在聽一個大牛的經驗分享會上曾聽到,在頁面滾動的時候可以通過計算,動態remove節點,保證用戶能看到的地方是有內容的,其他滾動卷去的部分就直接remove掉,等滾動回來的時候再加回來。這樣保證頁面上的節點不會太多,性能自然提升。我沒有嘗試這種方案,其中的注意事項也不好說。不過大牛成功了,必然是可行的。
總之得出一個結論,在移動設備上,要用瀑布流,一定要慎用,必須先有性能的解決辦法。
響應式布局與viewport
我們知道移動設備在渲染頁面的時候,會先在一個虛擬畫布上渲染,然后再縮放到設備的尺寸,比如IOS是在寬度為980px的虛擬畫布上渲染。我們看一些響應式設計的文章,也會知道在頁面<head>中要添加如下內容:
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>來保證頁面會按照設備的寬度進行渲染而不是使用虛擬畫布。然后便可以使用響應式設計的相關技術,彈性盒子、媒體查詢等,讓頁面適應設備寬度顯示。
然而我遇到了一個問題,因為頁面結構較復雜,在橫豎屏翻轉的時候出現了花屏,各種顯示不全,各種抽風抖動。當然是在android設備上。。。原因就是設備的寬度發生變化webview要進行頁面重繪,然而在重繪的過程中,由于頁面太復雜而不堪重負,繪到一半不管了。
因為當時該頁面的設計,會顯示圖片、音頻、視頻等媒體,并且是多個同時顯示,進行頁面精簡不可行。說來慚愧,面對緊迫的時間,我只好悄悄把上面的<meta>標簽刪掉,讓頁面還是在虛擬畫布上渲染,這樣渲染好的頁面在進行橫豎屏翻轉的時候,貌似是不會進行重繪的,只會由系統縮放一下,花屏的現象也不會發生了。只不過在豎屏下,頁面元素明顯小了。算是個下策。
像這樣的情況,個人覺的在頁面設計的時候就應該考慮到,若要進行橫豎屏翻轉,頁面盡量設計的精簡清爽。不過話說回來,移動應用上的頁面,精簡是一直需要且必須的。
盡量不要用別人的插件
不怕丟人的承認,我們做web App用的是jQuery,原諒我當時是個小白吧。。。如果早些知道我們的東西只需支持現代瀏覽器,無論如何也得試試zepto或是其他的小而輕的庫。不過既然用了,還是來面對這個現實吧。
小白的特征之一就是從素材網站收藏了好多jQuery插件,然后在項目中不假思索就用。我們的頁面是先在PC上用,然后才被告知要被webview引用的。這下麻煩來了,原先使用的好好的插件,一但跑在移動設備上,各種羊癲瘋發作。然后開始不遺余力的改源碼,過程簡直不堪回首。
比較典型的一個,我們的頁面中有富文本編輯器,當時選擇的是國內的一款開源編輯器KindEditor。我沒有詆毀這個項目的意思,它在PC上使用還是蠻好的。一上了平板,直接傻了,基本上廢了。環視網上,沒有一款為移動設備設計的編輯器。所以編輯器這東西,還是讓本地代碼來做比較合理。
另一個插件用的比較痛苦的是H5視頻播放的,用了mediaelement,它在官網宣稱支持各瀏覽器各平臺,然而真正效果卻并非宣稱的那樣。在android4.0以上的設備中都有各種兼容性問題。又是一頓改源碼。。。
所以得出的結論就是,如果某個組件可以自己寫出來,千萬別從網上找別人的,到頭來自己還得麻煩。倘若真的準備要使用,一定先做一個全方位的測評。包括能否與你的業務邏輯完美融合,能否支持你所需要的設備。
:hover偽類在移動設備上的特殊現象
我們在做鼠標懸停效果時,經常會用到:hover,無論用在<a>標簽或是其他標簽,現代瀏覽器都能正常兼容。比如我有一個圖標,在鼠標移上去之后想要一個陰影效果,可能會這樣寫:
.icon:hover{box-shadow:2px 2px 2px;}在移動設備上,是沒有鼠標指針的。當用手指點擊圖標的時候,可以出現陰影效果,這種效果也是可以接受的。但是當點擊完成后,手指離開了屏幕,圖標的hover效果卻沒有消失,依然是帶著陰影,就好像是有一個隱形的鼠標指針停留在圖標上一樣,實在是讓人不能理解。當再點擊頁面的其他部分時,圖標的hover效果就消失了,好像是隱形的鼠標指針移到了別的地方。
ipad和android設備上都有此現象。為了避免此問題,css中的:hover偽類就必須利用媒體查詢,只在桌面瀏覽器中生效。
ipad關閉屏幕造成的問題
ipad出于節約電量的設計,關閉屏幕后瀏覽器中的一些線程也會暫時關閉,等到開啟屏幕時再起。如果有需要持續執行的js代碼,關閉屏幕后便無法工作了。比如,要用setInterval函數實現一個計時功能,每隔一秒進行時間更新。當屏幕關閉后,計時函數就不能工作了,即關閉屏幕5秒種,你的計時器也將停止5秒。
如果是實現一些網頁動態效果,這倒沒什么影響。但如果你的計時器涉及到了業務邏輯,比如計的是一次考試的時間,那影響就大了。一個考生關閉屏幕后將可以使時間靜止。這是不希望發生的。所以,如果代碼中有用js進行計時,或其他需持續執行的任務。需要考慮到此問題。
對于計時器,我們可以隔一段時間與服務器進行時鐘同步,從而解決客戶端因關閉屏幕造成的計時誤差。
順便再加一句,使用ipad上的safari瀏覽器,在切換到別的標簽頁時,原標簽中的線程也會被停掉,跟關閉屏幕一樣的效果。
定位屬性與重繪的糾葛
在移動設備橫豎屏翻轉的時候,會進行頁面的重繪,ipad圖像處理性能較強,問題不大,但是形形色色的android設備性能不一,一些較差的在轉屏時經常會顯示不出來界面,或是出現花屏。比較明顯而且嚴重的情況是,當頁面上的元素使用了position:fixed或是position:absolute時,轉屏后該元素的定位將會錯亂,可能是轉屏時頁面所處的環境變動太大,渲染引擎計算的時候性能消耗太多,總是無法將這類元素正確顯示出來。
我的處理辦法是自己讓webview把這個元素再重繪一下,操作元素的屬性、className,或者是設置visibility均可觸發重繪行為。但這種方式也不是屢屢見效,有時候也無濟于事。沒辦法,android就是這么奇葩,太不穩定。所以實在不行我也會這么寫:
$(‘html’).css(‘visibility’,’hidden’); setTimeout(function(){$(‘html’).css(‘visibility’,’visible); },100);我懷疑webview的重繪是否真的進行了,所以直接讓頁面閃爍一下,這樣效果會好很多,一般情況都能重繪正確。
再糟的情況,實在用HTML解決不了了,可以去找客戶端的同學,讓他們操作webview,webview也可以進行重繪或者是直接reload。
不得不說的touch事件
在桌面瀏覽器上,基本的功能都是靠監聽click事件來完成的,移動設備上沒有鼠標指針壓根就沒有click這事件,不過對于這么重要的東西,引擎當然是做了相應處理。click事件在pad上可以很好的被響應。
但正如上面提到的,小白總是會使用一些現成的插件。。我用了一個彈出窗口插件,在桌面上可以用鼠標拖動,但是在pad上卻無法拖動了。移動設備上的引擎雖然對click做了很好的處理,但是對mousedown、mousemove、mouseup卻沒有理會,所以需要在代碼中對應的加上touchstart、touchmove、touchend事件。
有些現象是可以想出原因來的,但有些現象是那種根本就不講道理的,我這里也不知道如何描述。大概就是當touch事件和click事件同時被監聽,再加上頁面結構復雜等其他因素,就會出現各種抽風行為。
首先精簡頁面結構是最最重要的,沒有之一。其次對于不同設備的奇異現象,我也只能想辦法進行各種hack了。
明確要支持哪些設備
這一點跟技術無關了,是一個決策問題。ipad無論是2、3、4還是mini都比較穩定,兼容問題基本沒有。主要是android,系統版本從2.x到4.x不等,各種牌子:三星、華碩、聯想算比較主流的,其他是像昂達、酷派、粵教云。而且各品牌還有多種型號。再加上各廠家對android系統的無節操修改,瀏覽器內核都改。整個現在那叫一個亂啊。
所以在項目初期,明確要支持哪些設備是非常重要的。這樣就可以針對這些設備進行兼容性的測試。而不是今天客戶說要用哪個設備,我們就想辦法兼容哪個設備,真是會累死。還真有這樣的客戶,說我們就只使用千元以下的平板,性能那真是一個蛋疼。
?
經歷了一番痛苦的掙扎,秉著能解決就解決,解決不了就hack的原則,項目還真按期完成了。hack寫多了真是有種犯罪感啊!現在看著項目,真的有種假如上天給我再來一次機會的吶喊,不過一切都過去了。經驗教訓一大把,在此挑些典型的與大家共享。可能在專做移動開發的前端眼里,這些都是小兒科,但作為一個從小白走過來的程序員,這些經驗還是相當重要。
本文轉自呂大豹博客園博客,原文鏈接:http://www.cnblogs.com/lvdabao/p/3413345.html,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的与webview打交道中踩过的那些坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [游戏模版21] Win32 物理引擎
- 下一篇: java.net.URISyntaxEx