關於這個話題,本文並不准備詳述移動開發相關的一些通用技術,例如:viewport、rem、flexbox、媒體查詢等。這裡主要講述我們的hybrid產品策略、開發流程與規范、性能優化以及我們踩過的坑。而往往就是這些,網上相關的資料相對比較匮乏的,又缺少類似經驗文章,所以希望通過此篇文章,跟大家分享一些魅族團隊關於hybrid產品開發的經驗。
在以上背景下面,我們最終選擇了Hybrid App這個方案。那麼,接踵而來的問題就是,客戶端該如何訪問網頁前端資源?能不能就采用以前浏覽器訪問服務器網頁的方式呢?答案不是絕對的,當然也可以采用上述的方式。根據不同的業務需求,方式總是會有不一樣的。我們采用最多的是以下兩個方案:
該方案,會先在app裡面內嵌一份靜態資源,然後在用戶啟動app或者訪問html頁面並且符合一定條件的情況下,會發送請求去後台,詢問資源的情況。如果發現有更新,那麼就把最新的資源下載到本地,然後接下來用戶訪問的都是本地的靜態資源了。如果更新失敗,那麼他訪問的就是內嵌的或者已經下載好的靜態資源。
這個方案,其實就是采用HTML5的應用程序緩存(HTML5 Cache Manifest )。在這裡就不詳述了,網上關於這個的資料很多。值得注意的點,就是manifest的配置文件,需要配置正確的MIME-type,即 "text/cache-manifest" 。
一般是在開發一些活動或者專題頁面(上線時間短,ui變化多端)的時候,采用第二個方案。
而大多數的app頁面都是相對穩定,或者說是迭代開發,定期更新的,具備規律性,這種情況下,我們采用的是第一個方案。采用這個方案的時候,我們需要嚴格控制資源文件的大小,除了必要的壓縮之外,還可以把長期固定的資源提取出來,提前內置到app裡面。那麼,用戶每次更新資源時,只需要去服務器獲取變化的部分,大大減小了流量使用。
以上兩個方案,相對於每次都訪問服務器靜態資源來說,具有明顯的優點:
首先,客戶端加載某頁面,加載完成後(pagefinish),客戶端會調用前端提供的初始化方法(initParams)。通過該方法實現參數的傳遞和頁面的初始化。
我們目前使用fis3進行資源的壓縮、合並、添加 md5 戳等構建功能,對於使用了es6的項目,還需要用到Babel。在此基礎上,我們還開發了一些內部使用的基於fis3的插件。最終的目的,就是為了實現一條命令行,完成全部構建工作。
搭建本地web服務,使用的是nodejs+express。
從上圖我們可以看出,視覺設計、前端開發、客戶端開發、後台開發都在很大程度上實現了並行開發。
接下來,簡單描述一下前端開發怎麼實現和後台,還有和客戶端解耦,然後實現並行開發的。
首先,接口文檔(後台接口文檔和客戶端接口文檔)是不阻塞的前提。有了後台接口文檔,我們就可以依此構建相應的假數據,並且模擬相應的接口請求。而有了android接口文檔後,我們也可以模擬調用客戶端接口,至少保證了基本的邏輯是順暢的。所以,只要有了接口文檔,在進行到真正的聯調之前,前端、後台、客戶端這3者都是獨立開發,互不阻塞的。
然後聯調的話分三個階段:
這個階段的話其實只需要編寫一些假數據在本地,然後用ajax請求就行了。而android接口的調用,也是模擬調用便可。在這一階段,主要是為了確保前端邏輯基本跑通。
到了這已階段,我們需要的是訪問本地靜態資源,調用的卻是遠程服務器的接口。此種情況下,主要是要解決ajax的跨域請求問題。實現方式也挺多的,最簡單的就是設置一下浏覽器支持跨域。當然,你也可以使用nginx或者apache的反向代理來實現ajax的跨域請求。
這一步,已經到了提測前的最後一個步驟。這個時候,客戶端已經和靜態資源集成,然後調用的接口,無論是android接口還是後台服務器接口,都不再是模擬的了。
3種聯調狀態的切換,無論是在開發、bug定位、頁面調試等情況下,都是經常需要使用的。比如你在修改某個js邏輯bug的時候,首先,你一般都是從第二種聯調步驟開始的,畢竟在pc浏覽器上面調試bug還是要方便挺多的。然後,等到bug改得差不多了,才會把靜態資源push到手機上面,進行真機調試。
接下來就產生了一個問題,如何實現這3種聯調狀態的靈活切換呢?我們來看一段代碼:
2345678910111213141516171819202122為了實現3種聯調狀態的切換,我們基於fis3開發了一個插件,這個插件的功能也很簡單,就是處理上面這段代碼。
如何處理呢?首先看一下上面這段代碼,它可以分為兩個模塊,第一個是模擬代碼模塊(用和包起來),第二個是真實代碼模塊(用包起來)。模擬代碼模塊包括了一個模擬android接口的js文件引入、假數據的路徑以及模擬android調用初始化接口。真實代碼模塊可以寫一些真正上線需要使用到的路徑。這兩個模塊都不是必需的。
插件需要做的,就是把模擬代碼模塊去除,把真實代碼模塊釋放。
再來說說這樣做的好處,在模擬假數據聯調的階段,不需要使用到該插件,那麼此時根據上面的那段代碼,運行的就是模擬代碼模塊。而一旦我們要進行真正的接口聯調的話,就需要在fis3的parser階段調用該插件,以實現去除模擬代碼並使用真實代碼。而插件的使用,是在fis3的配置文件裡面進行配置的,通過fis3的media api,我們可以實現動態控制插件是否使用。
這是一個比較大的話題,像那些大家已經耳熟目染的雅虎十四條等頁面優化准則和資料,那是非常之多。我在這裡,會盡量從我們的項目角度出發,列舉部分我們所做的優化和解決的一些難題。
能不用的情況下,盡量不用。非得用的話,可以從多個角度進行優化。比如:
關於視口寬度的設置,目前比較通用的兩種方式:
第一種方式,簡單方便,不需要媒體查詢,不需要rem等,一個版本,適配所有機型。而且關於頁面精細度的問題,當視口寬度設置的比較大的時候,線條、字體等可以實現更加精細化的控制。
關於第二種方式,目前大部分大公司的移動端都是采用這種方式的。這種方式性能要比上一種高,畢竟少了一個縮放的過程,然後兼容性方面也是比較好的。
所以經過上述比較後,我們推薦第二種方式的。但是我們也發現,在和一些其他公司的人溝通過程,他們由於各種原因,還是采用了第一種方式。同時,我們也有一些項目,也是采用的第一種方式實現的。
而在采用第一種方式的情況下,我們發現,有些時候頁面加載的時候,繪制效果不是很好,會有一個從左到右平鋪的過程(其實就是一個縮放的過程)。關於這一點,其實是可以通過opacity的控制來優化效果的。
動畫這一塊,想必就是Hybrid app的一個痛點。想要在android內置的webview裡面,實現和android差不多效果的動畫,其難度實在是太難了,而且還會遇到挺多坑的。
比如,在做影院訂座頁面的時候,座位的選擇區域是要能夠進行縮放的。有了這個功能需求後,我們就要開始開發了。
關於縮放,我們首先想到的就是css3裡面transform屬性的scale值。接下來,我們就采用了scale方案進行開發。
動畫開發的歷程總是坎坷的,果然,問題出現了。選座區域的座位,在進行了手動放大後,變得相當的模糊。
也許你會想,是不是由於采用了圖片,然後圖片進行放大變得模糊,那也是情理之中的。好的,那麼接下來,我們嘗試著,直接使用css設置背景顏色的方式進行座位繪制。但是,這樣做的結果是,放大的時候,還是模糊了。
在這種情況下,我們就需要靜下心來思考一下了。到底是為什麼呢。
在描述原因之前,先要引入另外一個古老的css屬性zoom,並分別講一下這兩者的區別:
根據上面列舉的幾點區別,我們可以得出以下結論:
接下來講一下座位放大後變模糊這個問題應該怎麼解決。根據以上結論,得出兩個解決方案:
關於動畫的優化,就先講這一個列子,但是實際上,在我們的hybrid app開發過程中,還有很多的優化歷程,當然也踩了很多的坑。有興趣要了解的,可以試用一下魅族的生活服務,活動中心,電話黃頁等app,這些都或多或少的使用了hybrid方案進行開發。
目前前端技術日新月異,我們在不斷的嘗試一些新的技術(react、es6等),不斷的緊扣一些細節,不斷的優化再優化。這一切,不是短短一篇博文所能講完,後續我們會有新的內容加入進來一起討論學習。