GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

閒魚技術發表於2019-06-25

講師介紹

2012年應屆畢業加入阿里巴巴,主導了閒魚基於Flutter的新混合架構,同時推進了Flutter在閒魚各業務線的落地。未來將持續關注終端技術的演變及趨勢。

Flutter的優勢與挑戰

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

Flutter是Google開源的跨端便攜UI工具包,除了具有非常優秀的跨端渲染一致性,還具備非常高效的研發體驗,豐富的開箱即用的UI元件,以及跟Native媲美的效能體驗。由於它的眾多優勢,也使得Flutter成為了近些年來熱門的新技術。

通過以上的特點可以看出,Flutter可以極大的加速客戶端的研發效率,與此同時得到優秀的效能體驗,基於我的思考,Flutter會為以下團隊帶來較大的收益:

  • 中小型的客戶端團隊非常適合Flutter開發,不僅一端編寫雙端產出,還有效的解決了小團隊需要雙端人員(iOS:Android)佔比接近1:1的限制,在專案快速推進過程中,能讓整個團隊的產能最大化。
  • App在Android市場佔比遠高於iOS的團隊,比如出海東南亞的一些App,Android市場整體佔比在90%以上,通過Flutter可以將更多的人力Focus在Android市場上,同時通過在iOS端較小的投入,在結果上達到買一送一的效果。
  • 以量產App為主要策略的團隊,不論是量產ToB的企業App,還是有針對性的產出不同領域的ToC的App的公司,都可以通過一端開發多端產出的Flutter得到巨大的產能提升。

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

閒魚在以上的場景中屬於第一種場景,服務3億使用者的閒魚App的背後,開發資源投入並不多,與競對相比,我們是一隻再小不過的團隊,在這種場景下,Flutter為閒魚業務的穩定發展以及提供更多的創新產品給予了很大的幫助。

但與此同時,Flutter在設計上帶來的優勢同時又會帶來新的問題。所有的新技術都是脫胎於老技術的,Flutter也不例外,其身上帶有很多Chrome的影子。我們再做一層簡化,如果我們認為Flutter是一個使用Dart語言的瀏覽器容器,請大家思考一下兩個問題如何解決。

  • 如果在一個已經存在的App中加入Flutter,如何讓Native與Flutter進行無縫的銜接,同時保證相互開發之間的隔離性
  • 如果在Flutter的容器中,使用已有的Native UI元件,在Flutter與Native渲染機制不同的情況下,怎麼保證兩者的無縫銜接以及高效能。

閒魚的架構演進與創新

帶著上面兩個問題,我們來到閒魚場景下的具體Case以及解決方案的演進過程。

已有App+Flutter容器

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

在這種情況下,閒魚需要考慮的是首先要考慮引入Flutter容器後的記憶體壓力,保證不要產生更多的記憶體溢位。與此同時我們希望能讓Flutter和Native之間的頁面切換是順暢的,對不同技術棧之間的同學透明。因此我們有針對性的進行了多次迭代。

在沒有任何改造的情況下以iOS為例,你可以通過建立新的FlutterViewController來建立一個新的Flutter容器,這個方案下,當建立多個FlutterViewController時會同時在記憶體中建立多個Flutter Engine的Runtime(雖然底層Dart VM依然只有一個),這對記憶體消耗是相當大的,同時多個Flutter Engine的Runtime會造成每個Runtime內的資料無法直接共享,造成資料同步困難。

這種情況下,閒魚選擇了全域性共享同一個FlutterViewController的方式保證了記憶體佔用的最小化,同時通過基礎框架Flutter Boost提供了Native棧與Flutter棧的通訊與管理,保證了當Native開啟或關閉一個新的Flutter頁面時,Dart側的Navigator也做到自動的開啟或關閉一個新的Widget。目前Google官方的提供的方案上就是參考閒魚早先的這個版本進行的實現的。

然而在這種情況下,如果出現如閒魚圖中所示多個Tab的場景下,整個堆疊邏輯就會產生混亂,因此閒魚在這個基礎上對Flutter Boost的方案進行了升級並開源,通過在Dart側提供一個BoostContainerManager的方式,提供了對多個Navigator的管理能力,如果打比方來看這件事,就相當於,針對Flutter的容器提供了一個類似WebView的OpenWindow的能力,每做一次OpenWindow的呼叫,就會產生一個新的Navigator,這樣開發者就可以自由的選擇是在Navigator裡進行Push和Pop,還是直接通過Flutter Boost新開一個Navigator進行獨立管理。

Flutter Boost目前已在github開源,由於閒魚目前線上版本只支援Flutter 1.2的版本,因此需要支援1.5的同學等稍等,我們會在近期更新支援1.5的Flutter Boost版本。

Flutter頁面+Native UI

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

由於閒魚是一個閒置交易社群,因此圖片和視訊相對較多,對圖片視訊的線上效能以及記憶體佔用有較嚴格的要求。目前Flutter已提供的幾種方案中(Platform View以及Flutter Plugin),不論是對記憶體的佔用還是整個的線上流暢度上還存在一定的問題,這就造成了當大部分同學跟閒魚一樣實現一個複雜的圖文Feed推薦場景的時候,非常容易產生記憶體溢位。而實際上,閒魚在以上的場景下有針對性的做出了較大的優化。

在整個的Native UI到Flutter渲染引擎橋接的過程中,我們選用了Flutter Plugin中提供的FlutterTextureRegistry的能力,在去年上半年我們優先針對視訊的場景進行了優化,優化的思路主要是針對Flutter Engine底層的外接紋理介面進行修改,將原有介面中必須傳入一個PixelBuffer的記憶體物件這一限制做了擴充套件,增加一個新的介面保證其可以傳入一個GPU物件的TextureID.

如圖中所示,優化後的整個鏈路Flutter Engine可以直接通過Native端已經生成好的TextureID進行Flutter側的渲染,這樣就將鏈路從Native側生成的TextureID->copy的記憶體物件PixelBuffer->生成新的TextureID->渲染,轉變為Native側生成的TextureID->渲染。整個鏈路極大的縮短,保證了整個的渲染效率以及更小的記憶體消耗。閒魚在將這套方案上線後,又嘗試將該方案應用於圖片渲染的場景下,使得圖片的快取,CDN優化,圖片裁切等方案與Native歸一,在享受已有集團中介軟體的效能優化的同時,也得到了更小的記憶體消耗,方案落地後,記憶體溢位大幅減少。

目前該方案由於需要配合Flutter Engine的修改,因此暫時無法提供完整的方案至開源社群,我們正在跟google積極溝通整個修改方案,相信在這一兩個月內會將試驗性的Engine Patch開源至社群,供有興趣的同學參考。

複雜業務場景的架構創新實踐

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

將以上兩個問題解決以後,閒魚開始了Flutter在業務側的全面落地,然而很快又遇到新的問題,在多人協作過程中:

  • 如何提供一些標準供大家進行參考保證程式碼的一致性
  • 如何將複雜業務進行有效的拆解變成子問題
  • 如何保證更多的同學可以快速上手並寫出效能和穩定性都不錯的程式碼

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

在方案的前期,我們使用了社群的Flutter Redux方案,由於最先落地的詳情,釋出等頁面較為複雜,因此我們有針對性的對View進行了元件化的拆分,但由於業務的複雜性,很快這套方案就出現了問題,對於單個頁面來說,State的屬性以及Reducer的數量都非常多,當產生新需求堆疊的時候,修改困難,容易產生線上問題。

針對以上的情況,我們進行了整個方案的第二個迭代,在原有Page的基礎上提供了Component的概念,使得每個Component具備完整的Redux元素,保證了UI,邏輯,資料的完整隔離,每個Component單元下程式碼相對較少,易於維護和開發,但隨之而來的問題是,當頁面需要產生資料同步時,整個的複雜性飆升,在Page的維度上失去了統一狀態管理的優勢。

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

在這種情況下閒魚換個角度看端側的架構設計,我們參考React Redux框架中的Connect的思想,移除掉在Component的Store,隨之而來的是新的Connector作為Page和Component的資料聯通的橋樑,我們基於此實現了Page State到Component State的轉換,以及Component State變化後對Page State的自動同步,從而保證了將複雜業務有效的拆解成子問題,同時享受到統一狀態管理的優勢。與此同時基於新的框架,在統一了大家的開發標準的情況下,新框架也在底層有針對性的提供了對長列表,多列表拼接等case下的一些效能優化,保證了每一位同學在按照標準開發後,可以得到相對目前市面上其他的Flutter業務框架相比更好的效能。

目前這套方案Fish Redux已經在github開源,目前支援1.5版本,感興趣的同學可以去github進行了解。

研發智慧化在閒魚的應用

閒魚在去年經歷了業務的快速成長,在這個階段上,我們同時進行了大量的Flutter的技術改造和升級,在嘗試新技術的同時,如何能保證線上的穩定,線下的有更多的時間進行新技術的嘗試和落地,我們需要一些新的思路和工作方式上的改變。

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

以我們日常工作為例,Flutter的研發同學,在每次開發完成後,需要在本地進行Flutter產物的編譯並上傳到遠端Repo,以便對Native同學透明,保證日常的研發不受Flutter改造的干擾。在這個過程中,Flutter側的業務開發同學面臨著很多打包上傳更新同步等繁瑣的工作,一不小心就會出錯,後續的排查等讓Flutter前期的開發變成了開發5分鐘,打包測試2小時。同時Flutter到底有沒有解決研發效率快的問題,以及同學們在落地過程中有沒有Follow業務架構的標準,這一切都是未知的。

GMTC2019演講實錄|閒魚基於Flutter的架構演進與創新

在痛定思痛以後,我們認為資料化+自動化是解決這些問題的一個較好的思路。因此我們首先從源頭對程式碼進行管控,通過commit,將程式碼與後臺的需求以及bug一一關聯,對於不符合要求的commit資訊,不允許進行程式碼合併,從而保證了後續資料包表分析的資料來源頭是健康的。

在完成程式碼和任務關聯後,通過webhook就可以比較輕鬆的完成後續的工作,將每次的commit有效的關聯到我們的持續整合平臺的任務上來,通過閒魚CI工作平臺將日常打包自動化測試等流程變為自動化的行為,從而極大的減少了日常的工作。粗略統計下來,在去年自動化體系落地的過程中單就自動打Flutter包上傳以及觸發最終的App打包這一流程就讓每位同學每天節省一個小時以上的工作量,效果非常明顯。另外,基於程式碼關聯需求的這套體系,可以相對容易的構建後續的資料包表對整個過程和結果進行細化的分析,用資料驅動過程改進,保證新技術的落地過程的收益有理有據。

總結與展望

回顧一下上下文,

  • Flutter的特性非常適合中小型客戶端團隊/Android市場佔比較高的團隊/量產App的團隊。同時由於Flutter的特性導致其在混合開發的場景下面存在一定劣勢。
  • 閒魚團隊針對混合開發上的幾個典型問題提供了對應的解決方案,使整個方案達到上線要求,該修改會在後續開放給google及社群。
  • 為全面推動Flutter在業務場景下的落地,閒魚團隊通過多次迭代演進出Fish Redux框架,保證了每位同學可以快速寫出相對優秀的Flutter程式碼。
  • 新技術的落地過程中,在過程中通過資料化和自動化的方案極大的提升了過程中的效率,為Flutter在閒魚的落地打下了堅實的基礎。

除了本文提及的各種方案外,閒魚目前還在多個方向上發力,並對針對Flutter生態的未來進行持續的關注,分享幾個現在在做的事情:

  • Flutter整個上層基礎設施的標準化演進,混合工程體系是否可以在上層完成類似Spring-boot的完整體系構架,幫助更多的Flutter團隊解決上手難,無行業標準的問題。
  • 動態效能力的擴充套件,在符合各應用商店標準的情況下,助力業務鏈路的運營效率提升,保證業務效果。目前閒魚已有的動態化方案會後續作為Fish-Redux的擴充套件能力提供動態化元件能力+工具鏈體系。
  • Fish-Redux + UI2Code,打通程式碼生成鏈路和業務框架,保證在團隊標準統一的情況下,將UI工作交由機器生成。
  • Flutter + FaaS,讓客戶端同學可以成為全棧工程師,通過前後端一體的架構設計,極大的減少協同,提升效率。

讓工程師去從事更多創造性的工作,是我們一直努力的目標。閒魚團隊也會在新的一年更多的完善Flutter體系的建設,將更多已有的沉澱回饋給社群,幫助Flutter社群一起健康成長。

相關文章