“一套代碼,多端運行。”是很多開發團隊的夢想,直到 2018 年 12 月 5 日,谷歌正式發布 Flutter 1.0 版本,前端開發者向這一夢想前進了一大步。Flutter 僅用了不到一年的時間就在 GitHub 和 StackOverflow 上獲得了比 React Native 更高的知名度。Flutter 提供了一整套從底層渲染邏輯到上層開發語言的完整方案,有跨平臺、高保真、高性能等優點。也正因為這些革命性的優點,從發布到現在,它的熱度一路攀升,受到了很多開發者的熱切青睞。目前各大公司的 Flutter 落地實現各有不同,此次 InfoQ 記者采訪到了美團外賣的技術專家,Flap動態化項目的負責人董尚先,為我們分享了美團外賣采用 Flutter 的實踐與經驗。(相關視頻分享已在線上錄制完畢,預計在1月左右放出)
選擇技術棧要看業務特點
美團外賣的用戶端(下文用 C 端表示)和商家端(下文用 B 端表示)分別采用了不同的技術方案,原因是兩端的業務特點不盡相同。二者均有美團標準化的 web 容器,但 C 端的用戶量更大,對動態性要求更高,在低 pv 頁面用 React Native 來做頁面級的跨端動態化較多,在高 pv 頁面使用美團外賣自研的區塊級動態化和觸達提示,最終支撐外賣 C 端的動態性業務需求。
相比之下,B 端的頁面復雜度更高,C 端商品上的一些小標簽,小按鈕,在 B 端配置時有很深的層級和復雜的聯動組件。此外,B 端需要關聯到發配送,打印機等復雜邏輯,在實際開發時更加耗時。所以,B 端在技術選型時更看重跨平臺框架的性能瓶頸與雙端一致性。初期,美團外賣商家端也曾嘗試過用 React Native 作為跨平臺的技術方案,但過渡版本無法達到預期的要求,所以后期站隊 Flutter 技術棧。
確定技術棧后的思考
Flutter 的“多端一致”和“渲染性能”上的優勢讓其他跨端方案很難比擬。雖然 Flutter 的成長曲線和未來前景看起來都很好,但不可否認的是,目前 Flutter 仍處在發展階段,很多大型互聯網企業都無法毫無顧慮地讓全線 App 接入,而其中最主要的顧慮是包大小與動態化。
首先是包的體積問題,有很多大廠都做過 Flutter 的產物瘦身與包體積瘦身,美團也對此進行了嘗試,最終優化后 Android 的包體積降低了 95% 左右,IOS 降低了 30% 左右。
其次是動態化,其實動態化與包體積之間是存在聯系的:動態化可以帶來動態性,從而可以動態下發 bundle,就可以間接地減少包的體積。目前尚未看到成熟且大范圍落地的動態化方案。與此同時,美團外賣商家版的業務發展對動態化的訴求越發強烈,因此美團內部立項了 Flap 項目,目標就是支撐 Flutter 動態化能力。
為什么要用純 Dart 的動態化方案
可能基于其他語言做動態化的慣性思考來看,相對方便點的實現是用 Dart 做視圖 UI 部分,采用 JAVAScript 處理邏輯,事件回調的時候用 callbackid 來標識, 這樣的做法會帶來很多限制:
- 開發時要分開寫;
- 將存量的Flutter普通頁面 遷移到 動態化 成本太大;
- 運行時跨端通信損耗;
- 并且視圖和邏輯需要完全隔離的,視圖中的邏輯部分很難處理。
美團 Flap 項目的基本目標是做一套完整的業務解決方案,支持大廠應用的復雜業務,而不是一些重展示輕交互或是 UI 與動態模板這樣的方案。因此僅使用純 Dart 語言去做,在不引入其他技術棧的情況下,攻克視圖與邏輯一體化的動態化方案。這么做的好處基本就是上面列出的那些限制的反面:
- 可以保持開發習慣與普通 Flutter 一致;
- 寫完后的代碼可以在 Flutter 動態化和 Flutter 普通(AOT)上同時運行;
- 并且在運行時沒有跨端通信的損耗;
- 最大的優點是可以遷移存量頁面。Flutter 已經發展了一段時間,各個大廠都有大量的 Flutter 存量頁面,使用常規方案遷移至動態化就需要重寫代碼,使用此方式可以接近 0 成本將其遷移至動態化,不用更換語言重新開發。
純 Dart 所帶來的挑戰
Dart 是一種強類型、跨平臺的客戶端開發語言。具有專門為客戶端優化、高生產力、快速高效、可移植(兼容 ARM/x86)和原生支持響應式編程(Stream & Future)等優秀特性。Dart 語言既有靜態語言的特性,也支持部分動態語言的特性。
使用純 Dart 的方式開發動態化的難點在視圖邏輯一體化。相當于在 Dart 側開發一個針對 Flutter 語言特性的解釋器,需要對 Dart 整個語法特性有非常全面的認識。這里面的工作量也是很多的,我們在前期需要做很多的評估與拆解:
- 需要在整體架構上區分 “準備符號”與“運行”兩個階段;
- 需要考慮到視圖和邏輯兩個場景;
- 需要考慮到系統類與自定義類的兩種調用與加載方式;
- 需要用一套合理的 bundle 管理機制做好相應的隔離與約束。
除此之外,還需要同步搭建支撐動態化的技術生態與工具,包括 IDE 語法檢測插件(把問題前置到開發階段)、代碼生成工具、降級容災系統等。對開發同學的技術儲備要求較高。
業務落地只是目標之一,更重要的是在項目的實踐過程中發現框架存在的問題,完善各類語法特性支持,提高在復雜的場景下的兼容性,促進框架的完善。在不斷打磨中總結出合理的調試方案、操作步驟與協作方式,不斷提升開發效率與體驗。完善動態化基建及工具鏈建設,完成動態化流程的自動化與工程化,進一步降低轉換與開發成本。
實際進展與開源計劃
線上有些資料因為發布時間的問題,所以消息可能有滯后,現在已經 12 月上旬了,也快年底總結了,就以現在的口徑為準吧。 目前外賣業務已經真實上線了 100+ Flap 頁面,40+業務模塊。目前外賣商家端的跨端與動態化覆蓋度達到 90% 左右。 且已經在多個業務線實行需求動態發布流程,可動態上線的需求占比 60~80%,整體也是達到了年初時的預期。
至于開源應該到 21 年 Q2Q3。其實 sdk 很早就開發完了,之后是在通過業務落地來反哺 sdk 框架的打磨。 Flap 團隊之所以沒有第一時間開源,是因為覺得自己業務沒廣泛運用就開源是在“耍流氓”,后來我們也的確是優化了挺多問題。 下半年在能力和生態都建設的不錯,一些邊界的語法邏輯也都有了比較優雅的解決方案,接下來會在 Flutter 頁面“零成本”轉動態化的實施上再完善下,應該在 21 年 Q2Q3 左右開源。
Flutter 的使用體驗與性能
在開發時,Flutter 這種累磚塊的布局方式寫起來“很爽”,客戶端同學很好上手,大家反應寫起代碼來很快,在開發效率上已經有了不錯的表現。
Flutter 的雙端一直性做的很好,經常很多 Android 同學開發時拿 iOS 模擬器調試(因為 Android 調試一般都需要使用真機比較麻煩),iOS 模擬器開發完需求之后,拿 Android 設備再一跑大多都沒問題。Native 基本就是提供好一些端能力的橋就 ok 了。性能方面,Flutter 和 Native 也很接近,沒有 bug 的情況下,幀率也都是 59 朝上,渲染成功率也都是三個 9 以上。
在質量方面,目前外賣商家端的客戶端 crash 和 Dart 異常是分開采集的。Flutter 大量覆蓋之后 crash 占比中只有不到 10% 的量是由 Flutter 引起的,Dart 異常率不足千分之一。有時候上報的 Dart 異常并不會影響到用戶的體驗,例如有時候代碼缺陷關了一個彈窗,報了一個異常,但彈窗依舊正常關閉了等等。
總的來說,使用 Flutter 后,在效率、質量、性能三個關鍵點上都達到了的預期,今年年底前,美團外賣商家端應該會將 Flutter 動態化覆蓋至 80%以上。
跨平臺開發更應該是百花齊放
從 2010 年 Android 伴隨 Android 2.3 大火到 2013 年 iOS 伴隨 iOS 7 進入大家的視野以來,客戶端每年基本都有大新聞,2014 年 H5 的廣泛應用讓大量項目補充 Hybird 能力。 然后 2015、16 年 React Native 和 Weex 相繼開源,大家先后投入到跨平臺的開發。2017 年小程序和 PWA 先后登錄,但 PWA 在 2018 年并沒有達到人們期待的高度, 小程序則是穩扎穩打,移動端的流量也在逐步像小程序傾斜。但小程序的問題是巨頭公司太多框架太多,誰都想做最大的平臺,標準暫時統一不起來,還有一些路要走。 然后 2018 年 Flutter 1.0 出臺,并且逐步有后來居上的優勢,優點前面講過了,在 GitHub 上的 star 數也是逐步超過了 Weex 和 React Native。
董尚先表示,目前 React Native 還是很強大,因為 React 互通的生態很多。但從長遠目光來看,他覺得 Flutter 有成為商業 721 法則中的“7”的潛力。最大的特點 Flutter 是自渲染引擎,Flutter 的 embedder 層是非常輕薄的,同時也是目前跨端數量最多的,可以跨 6 端:
iOS / Android / Web / linux / mac / Windos 并且新系統 Fuchsia 也很大可能使用 Flutter 引擎 + Dart 語言。
目前許多大廠在同時使用多套跨平臺方案,而不是單從某些標準拋棄其他擇其一。未來一段時間內基本會過渡并維持到「內嵌 web 容器 + 少量 Native(端能力相關)+ Flutter / React Native 二選一+ 小程序」這樣一個組合。
致客戶端同學:學習跨平臺技術棧
對于客戶端同學,學習跨平臺技術棧基本是現在 ROI 最高的事, 你需要結合自身業務的特點和自己公司的大環境,深度學習一門跨平臺技術棧,可以是 Weex,可以是 Flutter,也可以是 React Native,然后先學明白一種,然后慢慢做到“一超多強”,其他的跨端也可以做到相對了解,寫個 Demo 之類的。
關于學習方式,我建議最好系統的學習,你可以找一個風格適合自己的的 Flutter 專欄或博主把他的公眾號的文章順序讀一遍。當然了,極客時間也是個很好的學習平臺,里面也是有很多大牛會把一門課系統的教學一遍十幾個課時,Flutter 在這里也有系統的學習課程,學習之后會有比較系統的技術儲備以及對應的自信。
作者介紹
董尚先,美團技術專家。2015 年加入美團,經歷了美團外賣的多個發展階段,先后任職于用戶端和商家端。曾主導外賣用戶端架構升級、無人值守的自動化流程體系等項目。致力于提升研發效率,同時也是移動端領域新技術的愛好者,負責多項新技術在業務落地中的難點攻關,目前擁有 10 余項國家發明專利。現作為 Flutter 動態化項目的負責人,探索客戶端 App 的最終形態。