本文來自於騰訊Bugly公衆號(weixinBugly),未經做者贊成,請勿轉載,原文地址:http://mp.weixin.qq.com/s/rNGD6SotKoO8frmxIU8-xw前端
本期 T 沙龍探討了移動端熱更新相關的話題。因爲沙龍時間的限制,本期咱們選取了美團的 Hybrid 化建設、去哪兒的跨平臺 ListView 性能優化、微博 Android 端熱更新踩過的坑話題。還期待熱更新、熱修復哪些話題?歡迎留言給咱們。也歡迎報名參加 T 沙龍分享本身開發中的心得。react
Hybrid 是移動端熱更新最經常使用的手段,限於 App Store 上架審覈時間較長,美團大衆點評也採起了該方案,歡迎來自美團大衆點旅遊業務 iOS 負責人吳卓分享《美團大衆點評 酒旅方面 Hybrid 化建設》。緩存
你們好!我是吳卓,很高興能來到 T 沙龍作這個分享,今天我將從 iOS 的角度跟你們一塊兒探討一下美團點評總體在 Hybrid 建設中作一些事情。安全
首先自我介紹一下:性能優化
我進入比較早,在 2011 年的 7 月份最先在美團實習。後來又繼續出國讀研,同時作一名兼職的開發者,在 2013 年的時候,作過 iOS 的獨立開發,有不少人把它做爲本身的一項事業去作。服務器
後來在 2014 年 12 月份從新加入美團,如今是旅遊 iOS 的負責人。微信
我負責的主要是住宿,度假,大交通,整個業務部門成立時間是相對比較晚,像住宿只作了三年,度假作了兩年,大交通是去年纔開始作的。快速迭代的可以給業務一個很是好的支持。cookie
今天的內容主要分紅四個部分:weex
第一個問題,咱們爲何要作 Hybrid 這個東西,其實剛剛提到整個業務發展很是迅速。在迅速發展中,咱們直接面臨瞭如下兩個很是棘手的問題:併發
第一個問題客戶端發版週期比較長,相信你們應該有相似的感覺,特別是在一個大公司裏面,迭代是相對固定的週期。另外在 iOS 裏面若是須要發版還須要 App Store 的審覈。
第二個問題是咱們公司一個現狀,前端資源嚴重不足。
首先,針對第一個問題,客戶端發版週期長,咱們但願經過一些手段脫離客戶端發版限制。
至於第二個問題,咱們但願把現有的前端和客戶端的同窗徹底結合起來,共同開發咱們主要的一個 APP 。
接下來說一下咱們 Hybrid 化總體的設計,整體上咱們是用一種 Native 和 H5 頁面強混合的模式。
若是在美團上買一個火車票,我不知道有沒有同窗買過。其實在美團上買一張火車票,有一部分是 Native 頁面,有一些是 H5 頁面,有一部分組件是 Native 作的,有一部分組件是 H5 作的。
若是使用這種方式作的話,咱們會遇到如下三個問題:
第一個問題是說如今的頁面裏面既有 H5 頁面,也有 Native 頁面,Native 頁面在 App Store 上面的, H5 相對比較靈活的。
因此有個問題,當H5上線以後,客戶端須要給H5提供一些跳轉的入口,這個跳轉的入口提供的應該是在不發版的狀況下去給出的,可以經過這種靈活的配置去實現 H5 到 Native 的一個過渡。
咱們來說一下美團 APP 的現狀,早在 2014 年美團 APP 其實大部分頁面是由 Native 編寫的,只有一些活動的展現頁面,是用 H5 形式的頁面展現的。
爲了實現頁面之間的解耦合,每一個頁面其實會有一個 URL 進行標識,根據每次跳轉到一個 Native 頁面,如今不少公司都採用相似的方式去作。如今是這樣的模式,那怎樣讓 Native 頁面過渡到 H5 呢?
咱們的方案是對這個跳轉去作一些擴展。本質上來講,客戶端這邊是從 URL 到 Native 頁面的路由表,咱們想辦法對跳轉的參數作的一些擴展,讓他可以支持跳轉到 H5 裏面,甚至跳轉到 URL 的頁面。
上圖的這個配置可以經過後臺進行下發,進行同時的更新,同時爲了作這個更新,咱們也爲這個路由配置作了一個前端的展現頁面。總體來講經過咱們在原有的這種跳轉模式下作了一些動態化的擴展,實現後續客戶端發版以後可以從後臺下發一些配置。
舉一個簡單的例子:
在美團 APP 買一個團購的訂單,用戶須要訪問列表頁,商家的詳情頁,建立訂單,最後購買成功。
若是咱們有一些新版本的上線沒辦法支持展現這些新的產品,對一個新的產品作一個 H5 的產品詳情和創立訂單頁面,把這個產品切換到走 H5 的流程最終的客戶端發版走這種 H5 的流程。
這樣不管是新的用戶還有沒有升級的老的用戶,都及時的訪問到咱們最新的產品。
在這兒簡單回顧一下,咱們作這個事情的一些設計思路。
剛纔說的配置下發只是在特殊狀況下作的,由於這種狀況是少數,不會天天全部的頁面都作這種事情,因此咱們並不會下發整個客戶端裏面的全部的配置,咱們只是把一些須要更新的內容作一些迴應,從後臺下發下去。
另一點是說上層的使用方,咱們內部會幫上層調用方,作好全部的相關的工做。
第二個問題,前端的 H5 頁面和 Native 頁面怎麼更新,由於他兩個是徹底不一樣語言開發的,其實這個方案的話咱們通常來講,把 Native 和 H5 的通訊機制約定爲,稱之爲橋協議。
這個橋協議,它是一個雙向的通訊方式。綠色部分是講 NativeJS ,這個是比較直觀的,在 WEB 應用裏面直接能夠調用這個方法。
可是 JS 調用 Native 的方法其實系統沒有提供一個很直接的方法,這個地方實際上是咱們須要解決的一個問題。
基本上, JS 調用 Native 本質上就是,給客戶端去傳遞一些消息,傳遞的消息格式實際上是比較隨意的,並且時間只要約定好就能夠了。
如今問題就是怎麼去傳?
這個問題,咱們當時在作的時候,其實調研了一下常規的方案來分析。有三個方案,我具體說一下:
第一個方案是經過 URL 攔截的方法
這個什麼意思呢?就是說,對於前端來講若是 JS 須要給應用傳消息,通常會開一個 Server ,會訪問一個地址,這個地址他的 Scheme 是一個特殊的 Scheme 。客戶端這邊會攔截到這種指令格式的 URL 需求,實現一個 JS 到 Native 傳遞消息的一個過程。
第二個方案叫主動輪詢
對於 JS 他須要把給 Native 傳遞的消息,轉化成一個 JSON ,客戶端這邊通常會開一個線程,每隔一段時間會調 JS 的方法,從這個方法裏面把 JS 須要給 Native 傳遞的消息所有取出來,取出來以後再去作相應的操做。
第三個就是 JSContext
前端能夠直接調用客戶端本地的方法。
咱們簡單對比一下這三種方案,第一個方案是 URL 攔截,他的優勢不管是哪一種 WebView 都是支持這種方式的,可是它的 URL 攔截延時高一點。第二個方案,主動輪詢,能夠併發處理多條消息,可是若是在客戶端性能開銷大,第三個方案是咱們如今正在用的,直接調用,可是他只支持 iOS 7 以上的系統。
接下來說一個很是重要的一個點,叫模塊化拆解,其實像咱們業務,每一個業務,都須要在上面定製本身的橋協議,實際上這個也方便管理。 咱們除了底下紅色,剛纔講的消息通信層之外,上面有模塊化的管理方式,像客戶端這邊,右側是客戶端這邊有模塊的管理模範,各個業務能夠本身把本身的模塊註冊在這個裏面,對應的JS層也有底層的封裝,左邊每個JS對應右邊每個模塊,會作一些模塊化拆解的工做。
再說說咱們怎麼前端和客戶端怎麼去開發,調試方式,其實如今方式是說,若是咱們須要新增一個橋協議的話,前端會先準備一個 Demo 頁面,把此次須要新加的橋裏面放在這個 Demo 頁面裏面,客戶端基於這個 Demo 開發,會給前端打一個模擬器,前端會用這個模擬器安裝包,本身完成剩餘的鏈條開發工做,這樣的好處是前端和客戶端能夠同時開發。
簡單回顧一下橋協議,橋協議通訊用最簡單最直接的方式進行調用,橋協議的實現,最關鍵一點支持可擴展的能力,開發調試咱們但願前端和客戶段可獨立並行開發。
第三個問題是指咱們的 H5 頁面怎麼去接近 Native 的體驗,在體驗差距上主要兩個方面。
第一個是前端的頁面代碼渲染,受限於 JS 的解析效率,以及手機硬件設備的一些性能。其實這個問題從應用開發的角度來講,是難以解決的。
第二個方面是 H5 頁面是從服務器上下發的,客戶端的頁面在內存裏面,頁面加載時間上面, H5 頁面和 Native 相比是有些差距的,可是這個差距咱們能夠經過一些方式彌補的,好比說咱們作了一些資源預加載的方案。
在資源預加載方面,其實也不少方式,我主要列舉了一些,基本上每種方式咱們都嘗試的作了。
第一種方式是說使用 WebView 自身的緩存機制。
若是咱們在 APP 裏面訪問一個頁面,短期內再次訪問這個頁面的時候,會感受到第二次打開的時候流暢不少,加載速度比第一次的時間要短。
這個就是由於,蘋果本身內部 Web 自身會作一些緩存,只要打開過的資源,他都會試着緩存在本地,第二次須要訪問的時候他直接從本地讀取,可是這個讀取實際上是不太穩定的東西,關掉以後,或者說這種緩存以後,系統會自動把它清掉,咱們無法進行控制。
基於這個 WebView 自身的緩存,有一種資源預加載方案,咱們在應用啓動的時候能夠開一個像素的 WebView ,事先去訪問一下咱們經常使用的資源,後續打開頁面的時候若是再用到這些資源他就能夠從本地獲取到,頁面加載的時間會短一些。
第二種方案是說,咱們本身去構建,本身管理緩存。
把這些須要預加載的資源放在 APP 裏面,他多是預製放進去的,也多是後續下載的。
問題在於前端這些頁面怎麼去緩存?
兩個方案,一個是,前端能夠在 H5 打包的時候把裏面的資源 URL 進行替換,這樣能夠直接訪問本地的地址。客戶端能夠攔截到這些網頁發出的全部請求作替換。
這個是咱們作的資源預加載的方案,採用的剛纔說的第二種方案,每當這個 WebView 發起資源請求的時候,咱們會攔截到這些資源的請求,去本地檢查一下咱們的這些靜態資源本地離線包有沒有。針對本地的緩存文件咱們有些策略可以及時的去更新它。爲了安全考慮的話咱們也作了一些預下載和安全包的一些加密的工做。
第一,咱們攔截了 WebView 裏面發出的全部的請求,可是並無替換裏面的前端應用的任何代碼,前端這套頁面代碼能夠在 APP 內,或者其餘的 APP 裏面均可以直接訪問,他不須要爲咱們 APP 作定製化的東西。
第二,這些 URL 請求,他會直接帶上先前用戶操做所留下的 cookie 而都可以留下來,由於咱們沒有更改資源的 URL 地址。
第三,整個前端在用離線包的時候,緩存文件的時候是徹底無感知的,前端只用管寫一個本身的頁面,客戶端會幫他處理好這樣一些靜態資源預加載的問題,有這個離線包的話,他加載速度會變快不少,沒有這些離線包加載速度會慢一些。若是版本不能跟他匹配的話,他的頁面也不會發生什麼問題。
這個是咱們當時作完以後,作完資源預加載以後的一些效果。好比說,這個圖裏面能夠看三個部分,一個是前端部分是沒有用資源預加載的下面,深色的部分是有資源預加載的效果,能夠看到,若是把有些資源打成離線包放在本地的話,其實他的加載時間是能夠縮短不少的。
另一點能夠橫向的看,其實像一二三,或者是這邊的一二三,三個頁面,其實本質上這三個頁面是一個購買流程人員,須要訪問到的路徑。
舉個例子,要進入第三個頁面,他必定會先打開第二個頁面,若是他打開第二個頁面,他必定會先打開第一個頁面。
前置篩選頁->車次列表頁->車次詳情頁
因此能夠看到,總體的加載時間是不斷的縮短的。這個也就符合咱們如今說的 Webview 自身是有一套緩存的。由於訪問後面頁面的時候有些資源其實在前面的頁面已經訪問過了,因此整個加載時間是不斷遞減的。
總結一下今天 Hybrid 化講的一些東西,包括咱們作的動態路由切換,包括咱們作的自定義橋協議,還有資源預加載的一些方案。
咱們其實如今整個頁面裏面既有 Hybrid 頁面也有 Native 頁面,那麼咱們是怎麼作區分的?
通常來講Hybrid的項目通常是用在一些快速迭代試錯的地方。另外包括有一些非主流產品的頁面,咱們傾向於用 Hybrid 的形式作.
可是像前端購買一些交易環節,特別核心的流程的話,咱們通常狀況下會用 Native 的形式去寫這些頁面,去提高,達到一個極致的用戶體驗。
最後想對比一下,簡單聊一下咱們現有的一些其餘方案,固然這些方案,各個其餘公司也正在去作。
第一個是 React 這邊,如今作了一些嘗試,由於 React 和安卓的平臺差別性是比較小,若是安卓端寫好代碼的話,成本很低,在項目發展初期的話,很好的去應用了這樣一種方式,減小成本。可是咱們後面發現,當中也遇到了一些問題,若是其餘同窗有解決方案的話也歡迎分享一下。
第一穩定性沒有達到一個很好的標準,固然也有多是咱們在使用上還存在一些沒有掌握的地方。
第二個問題是人力的問題,我以爲可能比技術問題更復雜一點,就是說,其實現有市面上,咱們很難在很短的時間內招到 10 個 iOS 的同窗去作咱們相應的開發。另外咱們即便招到一些人,可是現有的公司裏面培養體系,不太適合培養他們往更高層面發展。這個例子在後臺比較常見,像咱們如今美團點評是後臺絕大部分都是用 Java 去寫的,說白一點,就是說 Java 這個東西,仍是比較好招人,好大規模的去擴展去作事的。
Weex 方面,咱們內部有一些調研和學習,可是人力的問題仍是很凸顯。
咱們從業務發展的角度來講,也想得到一些動態性的一些東西。但願考慮說把有一些局部的模塊可以經過後臺下發的方式去作。咱們的名字叫動態模板化,可是目前仍是在作的階段,若是其餘同窗有相同的想法的話能夠共同作一些分享。
今天的分享先到這兒,謝謝你們!
Q1:我有一個問題,剛纔你說, JS 調用 Native 裏面,有一個相似輪詢。
吳卓:我那句話意思是說,一次只能攔截到一條消息,若是用輪詢的方式的話,能夠多條。由於最近應該不多有,最近幾期不多有美團的同窗來這兒講課,若是你們對美團的其餘的技術也興趣的話也能夠提出來,我若是知道的話儘可能也跟你們解釋一下。
Q2:這裏哪個頁面是 Hybrid 的?
吳卓:您下的是最近的版本嗎?舉個例子機票裏面選一個國際的城市,你能看到的就是, Hybrid 的頁面。國際城市裏面切換選擇日期的時候,看到的就是 Hybrid 的頁面。國際機票的列表也是用 Hybrid 走的。火車票裏面之前是用 Hybrid 作的,如今的話,主流改爲 Native 作的,固然若是出現一些緊急的狀況,咱們經過剛纔的切換系統切換到原來的 Hybrid 上。
另外若是您打開交通裏面的船票也是 Hybrid 的形式。由於我是作大交通業務的,因此說可能比較熟悉一點,向您推薦的也是咱們的產品。從您點擊船票開始後面都是 Hybrid 的頁面,固然這個頁面裏面有一些彈窗,有一些部分是Native作的。
Q3:你以爲 Hybrid 的模式和 Native 的模式,您以爲哪一種多是將來的發展趨勢,技術上。
吳卓:這是一個好問題。我只說一下我我的的觀點,不表明公司的觀點。首先我以爲從一個用戶體驗的角度來講,我更但願把全部頁面作成 Native 的,可是若是怎麼說呢,我以爲好比像 WebView,我剛纔說兩個問題,一個是說穩定性的問題,還有一我的力資源的問題,若是這兩個問題能解決的話,如今屬於觀望狀態,咱們其實能夠朝着這方面去作。由於我我的的觀點仍是說,全部頁面都能儘量的作成 Native 。在作 Hybrid 上,咱們想盡方式讓它接近 Native 。
Q4:大家是如何管理 Hybrid 代碼更新的呢?
吳卓:離線包的形式確定會增長內存的大小。咱們的團隊作增量的更新,以減小這種資源包下載的流量,這是戰略空間的問題。
第二個是離線包裏面有什麼,最主要是一些靜態資源文件,包括JS,CSS。基本上H5頁面訪問,就是在訪問一個頁面的時候須要加載這些資源咱們均可以從本地給他獲取。固然如今不是100%資源的離線化,一是考慮安全的因素,第二戰略方面的緣由有些技術無法作離線化。
更多精彩內容歡迎關注bugly的微信公衆帳號:
騰訊 Bugly是一款專爲移動開發者打造的質量監控工具,幫助開發者快速,便捷的定位線上應用崩潰的狀況以及解決方案。智能合併功能幫助開發同窗把天天上報的數千條 Crash 根據根因合併分類,每日日報會列出影響用戶數最多的崩潰,精準定位功能幫助開發同窗定位到出問題的代碼行,實時上報能夠在發佈後快速的瞭解應用的質量狀況,適配最新的 iOS, Android 官方操做系統,鵝廠的工程師都在使用,快來加入咱們吧!