與webview打交道踩過的坑

隨着HTML5被愈來愈多的用到web APP的開發當中,webview這一個神器便日漸凸顯出重要地位。簡要的說,webview可以在移動應用中開闢出一個窗口,在裏面顯示html頁面,css以及js代碼也能夠被解析執行,它使用的是咱們熟悉的webkit內核。android和ios都有相應的API,因此寫一份代碼在多個平臺運行的能力就是以webview爲基礎的。css

  今天咱們要聊的不是如何使用webview,而是筆者本人做爲一名前端工程師,在與客戶端開發人員經過webview打交道中遇到的種種神奇事件。html

  事情還得從去年提及,我仍是一個小白實習生的時候。當經理知道有webview這個神器以後,遂下令讓android組和ios組削減工做內容,全部共同的界面均由web組提供。而web組當時處於「傳統軟件公司無前端」的局面,頁面至關臃腫,壓根不適於移動設備。因而乎,不明局勢的經理指揮一個不明真相的小白實習生,帶着還沒使利索的jQuery,開始了所謂的Hybrid App開發。一個悽慘的故事拉開序幕,下面是在開發當中踩過的各類坑,記錄下來以供備忘。前端

webview與設備自帶瀏覽器同樣嗎?

  webview會調用系統自帶的瀏覽器內核來解析頁面。這是個真命題嗎?市場上的大部分平板電腦自帶瀏覽器爲webkit內核,webview使用的也是webkit內核,而且按一個應用的大小來看也不可能本身帶一個內核進去。因此是調用系統自帶的是沒錯的了。那我在一臺設備上,使用瀏覽器打開一個頁面和使用webview打開同一頁面,獲得的結果會是如出一轍嗎?固然是廢話了,都說了是調用關係。android

  假如真是廢話,那我也不必記下這一點了。由於從個人實際操做狀況來看,有些時候確實是不同的。瀏覽器裏一個樣,webview裏又是一個樣。ipad上狀況好些。在android品牌雜亂的設備上,此現象還真的出現不僅一次。尤爲是頁面DOM結構比較複雜的時候。ios

  有理由懷疑個人代碼不符合W3C規範啥的,但業界良心,W3C規範仍是不敢違反的。因此得出結論,webview與自帶瀏覽器解析的結果並非徹底一致,不能覺得頁面在瀏覽器中正常了,在移動設備上也就正常了。程序員

絕對要慎用的瀑布流

  大概是兩年前,瀑布流這個概念紅遍大江南北,各網站紛紛效仿,相應的文章、jQuery插件層出不窮。後來真正有思想的人開始質疑,提出咱們要學習的不是瀑布流的形式,而是思想,咱們須要的是真正適合本身產品的東西。後來,咱們經理也據說了瀑布流這個東西。。。web

  加!加瀑布流!咱們不要分頁列表那些東西!因而小白實習生網上各類搜索,找到了當時比較流行的叫作infinitescroll的jQuery插件。各類改源碼配合實現產品業務、各移動設備兼容性bug處理暫且放一邊。這裏要提的是與移動應用密切相關的一個問題。瀏覽器

  作移動開發的對閃退這種現象估計是咬牙切齒,移動應用的性能問題一直是不容小覷的。就webview來說,當html頁面的DOM元素不少,或者說層級關係較複雜時,對其的壓力是至關大的。再看看咱們的瀑布流,隨着頁面的滾動,不斷往上append節點,這對webview來講壓力極大,當節點數量到必定程度時,就發現頁面滾動不是那麼流暢,開始一卡一卡。別急,你在翻轉一下屏幕試試,瞬間崩潰,界面這個花了,內容像是繪製不出來同樣。由於在作橫豎屏翻轉時,解析引擎會進行頁面的重繪,這麼多的節點工做量可不小。ipad由於其優越的圖像處理性能表現還不錯,android設備上簡直一塌糊塗。服務器

  有什麼解決辦法呢?我在聽一個大牛的經驗分享會上曾聽到,在頁面滾動的時候能夠經過計算,動態remove節點,保證用戶能看到的地方是有內容的,其餘滾動捲去的部分就直接remove掉,等滾動回來的時候再加回來。這樣保證頁面上的節點不會太多,性能天然提高。我沒有嘗試這種方案,其中的注意事項也很差說。不過大牛成功了,必然是可行的。前端工程師

  總之得出一個結論,在移動設備上,要用瀑布流,必定要慎用,必須先有性能的解決辦法。

隨着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不管是二、三、4仍是mini都比較穩定,兼容問題基本沒有。主要是android,系統版本從2.x到4.x不等,各類牌子:三星、華碩、聯想算比較主流的,其餘是像昂達、酷派、粵教雲。並且各品牌還有多種型號。再加上各廠家對android系統的無節操修改,瀏覽器內核都改。整個如今那叫一個亂啊。

  因此在項目初期,明確要支持哪些設備是很是重要的。這樣就能夠針對這些設備進行兼容性的測試。而不是今天客戶說要用哪一個設備,咱們就想辦法兼容哪一個設備,真是會累死。還真有這樣的客戶,說咱們就只使用千元如下的平板,性能那真是一個蛋疼。

 

 
  經歷了一番痛苦的掙扎,秉着能解決就解決,解決不了就hack的原則,項目還真定期完成了。hack寫多了真是有種犯罪感啊!如今看着項目,真的有種假如上天給我再來一次機會的吶喊,不過一切都過去了。經驗教訓一大把,在此挑些典型的與你們共享。可能在專作移動開發的前端眼裏,這些都是小兒科,但做爲一個從小白走過來的程序員,這些經驗仍是至關重要。
相關文章
相關標籤/搜索