Android Hybrid App四大坑

首發個人博客:Android Hybrid App四大坑css

首先解釋下題目,Hybrid App,混合應用,表明平臺PhoneGap,通常指使用原生包裝Web頁面開發的應用。與原生應用相比,主要用戶界面和業務邏輯都是用Web技術也就是HTML+CSS+Javascript實現的;與Web應用相比,Web部分打包在應用內部,使用時不須要網絡。html

順便說一句,不少解決方案其實不算Hybrid,好比Adobe AIRTitaniumMono,這些都是使用某一特定技術開發跨平臺應用的工具,最終產品都是編譯成原生來跑的。前端

咱們沒有選擇PhoenGap爲技術基礎(我對此並不滿意,我認爲以PhoneGap爲基礎能夠少走一些彎路,少花一些精力,還能產出不少有價值的副產品),而是自行開發原生框架,主要目標平臺是Android——嗯,就是那個從系統版本到模塊組合都巨分散的Android,能夠這麼說,坎坷從立項的那一刻起就已經註定了……接下來,便請聽我一一講述:Android Hybrid App四大坑。(此文主要針對Android 4.3及以前的webview,部分瀏覽器好比Chrome已經改善了具體實現,因此Web App其實環境不錯。)android

遊戲泡泡v0.2首頁截圖

前端代碼開源就好,https://github.com/Dianjoy/gamepop,要跑起來須要修改config.js,把if (debug) {}的內容刪掉。css3

缺乏標準flexbox

Flexbox是CSS3裏面一項很是重要的改進,大大改善了佈局工做。惋惜從草案到終案時間跨度太長,因而市面上絕大部分設備只支持display:-webkit-box。這給上圖中圖標區域的佈局帶來了難處,最終只能混合使用兩種佈局,display:inline-blockdisplay:flex。須要注意,inline-block元素之間,若是在代碼中有空格換行符的話,渲染時會有約0.25em~0.5em大小的間隙,因此想一行4列每列width:25%的話會放不下致使折行。開始我在其父元素中設置font:0/0 a,大部分手機都OK,中興ZTE795就不行,擦,上次也是它……後來我索性把全部空格和換行符都幹掉,終於OK了。git

這段代碼演示inline-block佈局時父元素字體對子元素之間間歇的影響。github

<iframe src="http://jsfiddle.net/meathill/9Uk5Y/embedded/result,html,css,js/presentation/" height="200" width="100%" allowfullscreen="allowfullscreen" frameborder="0"></iframe>

因此,對於多行多列的grid佈局,咱們要謹記:web

對父元素使用display:flex; flex-direction: row; flex-wrap: wrap;在現代瀏覽器和Android4.4以上的系統中,能夠取得完美表現。
使用display:inline-block; box-sizing: border-box; vertical-align: top;,而且在代碼中移除塊與塊之間的空白字符,避免換行,保留合適的邊距。
遺憾的是,低版本的webview中,高度不會自適應,除非使用js進行計算,否則仍是儘可能避免在元素下方畫線的舉動。瀏覽器

tap vs click

(這個問題簡直使人髮指。)咱們知道,不少瀏覽器默認行爲都依賴click事件觸發,好比超連接、input[type=radio]的選中,等等。在4.4以前的webview中,click比真實操做延遲約300ms觸發,會帶給用戶明顯的延滯感。爲了提高用戶體驗,咱們多數使用tap事件部分替代click事件,以便及時響應用戶操做。可選方案不少,Hammer.jsFastclick,甚至Zepto都有封裝。服務器

因而新的問題出現了。好比咱們用<a>實現了一個刪除按鈕,tap時,刪除當前元素,而且將按鈕重置爲下載按鈕,href爲下載的url。用PC開發時一切正常,但到真機測試就會發現,由於tap是即時的,新按鈕馬上替換了舊按鈕,300ms後,click事件在新按鈕上觸發了,結果又開始下載……再好比,圖層中有個後退按鈕,點擊後,圖層移除,露出下面覆蓋的部分,若是在tap的位置上恰好有一枚連接,此時就會觸發click,頁面跳轉……以及,上次總結說的下載連接不觸發click,問題也同樣,只不過翻過來,click該觸發的時候,被圖層擋住了,因此沒有觸發。

展示誤觸click的bug的原理

解決方案基本圍繞「如何熬過300ms」,和「甄別事件對象」來設計。

仍是上面兩個場景,第一個,按下以後,setTimeout 400ms(以防萬一)後再替換按鈕;第二個,給圖層加一個消失的動畫,持續400ms,保證click觸發時圖層還在。可能你們有疑問,爲什麼不乾脆禁掉click事件,前面說了,不少瀏覽器默認行爲依賴click事件,禁掉以後又會引起別的問題。

另外一個解決方案是甄別事件對象,在用戶touchstart的時候,記下event.target,等到click觸發時,對比,若是不一致則認爲是抽風,event.preventDefault()。我更推薦這種作法,畢竟400ms也不算短。不過要注意,<label>在響應click時,會自動觸發它for的元素的click,因此要用新增的control屬性進行二次對比,以避免誤傷。

position:relative;居然搶事件

這個問題解決起來容易,排查時沒少花時間。表現爲,一個按鈕,就在那裏,但怎麼點都沒用。後來只好追蹤全局事件,發現事件的對象並不是按鈕,而是按鈕下面被遮蓋的層。很奇怪,我知道translateZ可能致使這個問題,不過如今徹底沒用到;並且下面的圖層實際並無那麼長(參照上圖中,內容列表和下面的三個按鈕,就是那裏),列表的底部是bottom:60px,恰好應該把<footer>的三個按鈕空出來。

而後我開始懷疑position:relative;,由於只有這個東西會影響佈局。把它點掉後,按鈕果真能夠點了,因而我給<footer>也加上了position:relative;問題就這樣解決了。我以爲這確定又是個Android Webview的Bug,由於我並無給下面層裏的元素設置z-index,只有position:relative。總之,若是按鈕點擊沒反應,儘早看看事件對象是哪一個,說不定被哪一個層搶走了。

各類待實現的API

caniuse.com是個神器,我在使用某個API或者CSS屬性時不太有把握的話,都會去查一下。然而,誰又知道Android Webview默認不少API都沒開呢?大到localStorage,小到alertconfirm,都須要主動開放,否則就無法用。測試的時候又很難查,原生的環境多不在我這兒,配也不太容易,你們的習慣都不一致,只能等對方反饋過來錯誤信息,我到代碼裏查,但經常死活看不出來哪兒有問題。

後來認清現實就好辦,Android Webview實際上是個半殘廢,有不明白的問題,多半是API實現不全致使的。最簡單的辦法是用modernizr之類的工具進行特性檢測,或者在Weinre、Adobe Inspect CC裏直接敲API。總之,別懷疑本身,基本都是Android Webview的問題。

這也是我爲何但願以PhoneGap爲基礎的緣由:PhoneGap已經按照規範實現了大部分API。插件庫也很豐富,好比GA——說到這個,咱們想實現一個簡單的統計,由於老闆嫌GA太大,因此乾脆使用一樣的接口,只請求一下咱們的日誌服務器,留下條日誌就好,結果咱們驚訝地發現:Android裏原生給Webview環境增長API,方法的參數不能多也不能少,否則就報錯,真奇葩——能夠省下不少時間。產出的結果,還能夠分享到社區一部分,對於咱們公司,也能增長了很多開發者資源。

總結

早先別人鄙視Hybrid App的時候我也各類不服,心說「大家丫懂毛啊就指手畫腳的說不行」;如今經歷了各類大坑小坑連環坑以後,個人想法已經變成了「大家丫懂毛啊不就是一不當心蒙對了麼」。

Hybrid App開發會遭遇比原生和Web App更多的坎坷,這我有心理準備;如此多的坑無形中也在提高個人我的價值,我對此甚至隱隱有些高興。不過我仍是但願這段混亂之治儘快過去,Android平臺不要再分裂了,高版本系統儘快普及,全部前端開發的日子都會好過許多。

如今,若是可能的話,儘可能以PhoneGap爲基礎進行開發,能省不少時間和精力。對於前端人來講,更是能把測試環境搬到本地,實在是很是大的幫助。

Android 4.4時再次分裂,以後使用blink做爲webview的基礎;以前則是webkit,前者不管CSS仍是API都有更佳表現,Nexus 5基本沒怎麼改就都測試經過了。因此未來老羅的錘子手機開賣我必定買一臺支持他,由於他良心的採用4.4爲基礎,對前端真是個可貴的好消息。

相關文章
相關標籤/搜索