Flutter + Dart三端一體化動態化平臺實踐

陶然陶然發表於2023-02-21

   1 引言

  FairPushy 是基於Flutter+Dart三端一體化打造的動態更新平臺,為Flutter動態化場景提供動態分發能力,全方位降低上手成本,提升開發體驗。實現了動態化資源產物自動化打包和動態分發的能力,讓開發者擺脫了技術棧的壁壘,並且系統輕量化、簡單易用。

   2 Flutter動態化

  Flutter相信大家一定不陌生了,它的設計初衷,就是允許在各種作業系統上覆用同樣的程式碼,例如 iOS 和 Android,用Flutter寫的軟體程式就能夠在不同的平臺上擁有原生體驗的高效能應用。得益於他在每一個平臺上,都會包含一個特定的嵌入層,從而提供一個程式入口,程式由此可以與底層作業系統進行協調。從2018年2月17日釋出的beta1版本到現在3.0版本已經過了4個多年頭。之所以這麼火熱無疑離不開他可以跨平臺的特性和較高的UI效能,幾乎滿足的所有跨平臺開發者的幻想,但是包大小和動態化問題也一直爭議不斷。

  58也自研了Flutter動態化Fair,他是支援不發版(Android、iOS、Web)的情況下,透過業務bundle和JS下發實現更新,方式類似於React Native。Fair的UI渲染是無損的,可以做到畫素級別的還原,如下圖:  

  動態化帶來的好處毋庸置疑,會及時高效的滿足業務需求,提升使用者體驗同時也會減少初始包的大小,提高裝機率。如果出現質量問題也可以在不發版的情況快速得到解決。然而Fair動態化的bundle和JS產物需要有一個Web平臺來管理分發,涉及Server、Web和Flutter外掛,Flutter是基於Dart語言,Dart語言官方給的定義是”是面對物件的、單繼承的語音他的語法與C語言有點類似,可在任何平臺上開發快速的應用程式“因此我們打算全部用Dart語言來開發動態化平臺。

   3 FairPushy選型

  目前開發Server的語言已經很成熟了,比如常見的JAVA、Node.js、Go、PHP、Python等(排名不分先後)。從這幾年的排行榜看Java仍穩坐鐵王座第一名,是最受歡迎的語言,這肯定離不開他的語言特性:是一種簡單的,物件導向的,分散式的,健壯安全的,可移植的,效能優異、多執行緒的動態語言。PHP(PHP: Hypertext Preprocessor)即“超文字前處理器”,是在伺服器端執行的指令碼語言,尤其適用於Web開發並可嵌入HTML中。PHP語法學習了C語言,吸納Java和Perl多個語言的特色發展出自己的特色語法;該語言當初建立的主要目標是讓開發人員快速編寫出優質的web網站比較適合用於個人網站、企業官網等輕量級的專案開發。Python語法和動態型別,以及解釋型語言的本質,使它成為多數平臺上寫指令碼和快速開發應用的程式語言。Go(又稱Golang)是Google開發的一種靜態強型別、編譯型、併發型,並具有垃圾回收功能的程式語言。而Node.js和Dart的介紹如下:

  Node.js: 一個基於 Chrome 的 JavaScript 執行時構建的平臺,使用了一個事件驅動、非阻塞式I/O模型,讓JavaScript 執行在服務端的開發平臺,如果你有前端開發經驗無疑更適合用Node.js來開發服務端。

  Dart: 一種新的 Web 程式語言,包含庫、虛擬機器和工具。Dart 是一個內聚的、可擴充套件的平臺,用於構建在 Web(您可以使用 Polymer)或伺服器(例如使用 Google Cloud Platform)上執行的應用程式。使用 Dart 語言、庫和工具編寫從簡單指令碼到功能齊全的應用程式的任何內容。

  語言沒有絕對的好壞,需要根據業務和成本選擇合適的。單領出來Node.js和Dart介紹主要考慮使用Flutter開發專案的大部分是前端和移動端同學,具體選擇那個需要從業務的場景中考慮,如果說我是移動端開發Flutter專案對Dart語言相當熟悉這樣就更適合用Dart來開發Server,反之如果你是一名前端開發則用Node.js更合適些。既然是開發Flutter專案如果能使用Dart開發後端服務最大的優勢也就是不需要學習新的語言、最大程度保證平臺一致性、減少語言的學習成本和重複工作成本;因此我們打算全部用Dart語言來開發動態化平臺。

   4 FairPushy架構  

  整體設計是以Dart語言為支撐,Dart語言是物件導向的,特點和平常用的語言有類似的語法、執行時環境變數,可以執行在瀏覽器、dart虛擬機器和移動裝置上。並且同時支援 JIT(Just In Time,即時編譯)和 AOT(Ahead of Time,執行前編編譯)的語言之一。上圖的FairPushy大致可以分為四個方面如下:

  1. Dart support: 其中包括dart:core實現基礎的內建型別、集合以及其它的一些核心功能和isolate實現併發程式設計

  2. Dart Server: 主要包括資料庫和連線池、ORM、RPC框架的建設和對Web和移動端提供上層業務的的HTTP介面的支撐

  3. Flutter Web和Fair Sdk:Flutter Web提供Fair產物的打包上傳、環境切換和動態化編譯功能,Fair SDK主要負責Fair資源產物的下載、快取和載入功能

  4. 運維和研發支撐: 因為整體的設計語言是相同的所以一些研發的基礎元件也可以共用比如一些日誌庫、網路庫、Crash監控和效能監控。

  由於篇幅問題本分只分析Dart Server開發的相關知識點,偉人曾經說過:你要想知道梨子的滋味,就要親口嘗一嘗,但是任重而道遠。Dart Server實現的難點:

  基礎元件建設:如何寫HTTP介面、如何設計SQL表、如何連結遠端資料庫等等

  生態建設:客戶端同學初次接觸到後端的知識,需要了解後端如何開發、部署和排查解決錯誤

  監控系統:程式碼出現異常錯誤如何監控和告警?

  併發問題:Dart語言編寫的後端服務是否可以滿足高併發下業務請求?

   5 Dart Server實踐  

  整體從初次接觸後端服務開發者角度分析主要分為兩個流程,開發階段和部署階段:

  開發階段:需要進行Dart環境的配置和Studio安裝。我們封裝了基於Dart Server基礎庫建設,其中最主要的是日誌庫、路由框架和Widget封裝。其次是生態環境的建設這也是Dart Server最難的地方。像Java有Spring全家桶可以很方便的進行業務需求的開發,而Dart Server生態環境建設大致可分為異常的監控、RPC框架、ORM框架和MySql框架。具備了這些功能就可以進行業務需求開發了。

  部署階段:藉助的58雲平臺完成服務的自動化部署,需要構建基於Dart環境的基礎映象來執行服務。之後透過Docker編寫指令碼透過Git分支拉取Dart Server的業務程式碼,然後執行run/server.dart指令碼來服務的啟動。啟動後可以透過監控服務監聽業務是否正常執行,如果出現閾值之外的異常會透過告警組通知開發人員。

  5.1 基礎能力建設

  讓Dart語言開發後端服務需要一些基礎庫,比如如何連結遠端資料庫?如何接收HTTP介面請求?如何處理異常的錯誤?等等。具備了這些基礎庫就可以實現一些簡單的介面開發了。在Flutter中一切皆可Widget,我們為此保持了與Flutter統一的編碼風格,在寫後端介面也可以和寫前端頁面一樣一切皆可以Widget。在服務啟動的時候需要註冊ServerPages,所有的HTTP介面需要在此註冊。原理和Flutter中的路由配置類似。其中name表示介面請求的路徑,page表示實現這個介面邏輯具體實現類,method表示HTTP請求的方式Get或Post等,needAuth是一個bool值,表示這個介面是否需要登入鑑權,true則會校驗Token如果不滿足會返回鑑權錯誤的Response。

  我們封裝了FairServiceWidget可以透過繼承實現server()來很方便的獲取HTTP介面請求的引數;PatchDao是ORM框架的模型的實現類後面會詳細介紹,可以透過他來實現資料庫的增刪改查,searchBundleId是查詢資料的具體SQL語句,最後透過toBundleJson來實現資料的序列化。以動態化平臺實際的功能獲取Bundle資源介面為例,一個完整的HTTP介面請求大致如下1、繼承FairServiceWidget實現Server()處理業務邏輯2、透過request_params獲取請求的引數和引數的校驗3、引數正確會透過PatchDao查詢遠端資料庫資訊4、獲取bundle資料後會進行Response封裝返回:

  5.2 Dart併發問題

  Dart是單執行緒執行,也就是說一旦Dart函式開始執行,就會一直持續直到結束,Dart函式不能被其他Dart程式碼中斷。不過Dart可以透過 async-await、isolate 支援併發程式碼程式設計。Dart 程式碼並不在多個執行緒上執行,取而代之的是它們會在 isolate 內執行。每一個 isolate 會有自己的堆記憶體,其各自的GC不會影響到其他isolate的,從而確保 isolate 之間互相隔離,無法互相訪問狀態。由於這樣的實現並不會共享記憶體,所以不需要擔心 互斥鎖和其他鎖。所以我們可以透過把用記憶體空間較大且生命週期較短的介面放到isolate中,這樣即使另外一個isolate GC了並不會對我們正常的業務流程造成影響。  

  在使用 isolate 時, Dart 程式碼可以在同一時刻進行多個獨立的任務,並且使用可用的處理器。Isolate 與執行緒和程式近似,但是每個 isolate 都擁有獨立的記憶體,以及執行事件迴圈的獨立執行緒。Event queue能夠確保同時處理多個任務。event loop的工作就是從event queue內拿一個event然後處理它,一直重複這個操作直到queue裡全部處理完畢。event queue內的event有可能是檔案I/O、timers等等  

  如圖所示,Dart應用程式在其main isolate執行應用程式的main()函式時開始執行。main()退出後,main isolate開始逐個處理events queues的內容。一個Dart應用程式只有一個event loop,但是有兩個Queue,event queue包含所有的外部事件,I/O、timers、兩個isolates之間的訊息等,microtask queue則表示一個短時間內就會完成的非同步任務。它的優先順序最高,高於event queue,只要佇列中還有任務,就可以一直霸佔著事件迴圈。microtask queue新增的任務主要是由 Dart內部產生。  

  5.3 生態完善

  Dart開發後端服務是空白的,需要一些元件才能讓開發更便利,比如遠端SQL連結、連線池、日誌監控和ORM等。當然業界也有一些開源的框架可以直接使用。因為篇幅受限,所以我們找其中一個主要的點來分析:ORM框架在Dart Server中的實踐。

  ORM 的英文是 Object Relation Mapping,物件關係對映,是 RDBMS 和業務實體物件之間的一個對映,把底層的 RDBMS 封裝成業務實體物件,提供給業務邏輯層使用。ORM框架提供了一種持久化模式,在Java中比較常見框架是MyBatis,他可以高效地對資料庫進行訪問。  

  在Dart Server中實現ORM需要封裝對資料庫的連線、資料物件對映和增刪改查等,可以按照前面介紹的獲取Bundle資源介面為例子,需要先建立PatchDao類,內部需要實現了對資料資訊的封裝,只需要填寫要操作的表明、對映的物件類和關鍵查詢語句即可。比如要更新補丁表資訊則可以直接傳入最新的對映的物件類實現更新即可。

  可以看到上面在做update的sql語句是透過拼接處理,我們提供一套公共sql語句模板,然後在具體實體物件操作的時候將實體物件的屬性名稱和屬性值當作引數拼接進去,組裝成完整的sql語句。如果查詢操作則會根據返回的資料對映成Dart物件類,所以資料驅動返回的資料通常都是以資料為核心的資料集合,我們透過ORM框架將類物件和資料庫返回的列資料進行一一匹配獲取,然後賦值到物件上:

  ORM還為能我們做了什麼?ORM框架做的最多的便是“快取”。因為資料庫操作是要和硬碟打交道的,而程式是在記憶體中執行的,操作記憶體的速度要比操作硬碟快數十倍以上,可見一個訪問量較高的大型系統很容易由於資料庫操作過於頻繁而拖慢整體速度,從而影響系統的使用。因此,ORM框架還需要幫助我們減少資料庫的訪問,加快系統速度。

  5.4 動態化線上編譯

  Flutter Fair動態化產物有json和js檔案需要上傳到CDN服務動態分發到APP上來實現動態化功能,其中產物需要在Flutter Web平臺進行打包上傳,目前支援兩種方式:

  手動上傳:需要開發者在本地編譯器編譯生成Fair產物,到Flutter Web平臺手動上傳打包好的產物包

  自動上傳:開發者無需關心Fair產物,只需要在Flutter Web平臺配置專案Git地址、Flutter版本等,點選線上編譯即可觸發自動化構建和Fair產物上傳  

  如圖所示,自動化上傳Fair產物由開發者在Flutter Web平臺配置構建資訊,轉到Dart Server 進行編譯處理,根據Web平臺的構建配置資訊會進行入庫操作,把Git地址、Git分支和Flutter版本等與本次建立的Fair資源做關聯記錄。之後會進行環境清理、拉取填入的GIt專案地址到伺服器,執行flutter pub get和flutter pub run build_runner build命令生成Fair產物,關鍵指令碼如下:

  拿到Fair編譯產物後會上傳到cdn,然後獲得cdn上傳後的url,把url更新patch_online_build資料庫表中。至此完成了整個動態化編譯流程。其中需要藉助Docker來完成一部分的指令碼執行,docker是一個開源的應用容器引擎,基於go語言開發並遵循了apache2.0協議開源。docker可以打包應用以及依賴包到一個輕量級、可移植的容器中,然後釋出到任何的linux伺服器,也可以實現虛擬化。容器是完全使用沙箱機制,並且容器開銷極其低,感興趣的可以查閱資料瞭解下。

   6 總結與展望

  本文分享主要以Flutter Fair動態化為背景的熱更新平臺實現方案,透過對Dart Server研究和實踐確認Dart開發後端服務的可行性,對於開發Flutter的客戶端和前端同學可以擴充視野和提高整體化思維,並且極大的減少溝通成本。“任總而道遠”需要實現的功能還是有很多,並且需要開發者經過不停的迭代與最佳化才能越做越好,這個過程將會是一個漫長且繁瑣的過程。

來自 “ 58技術 ”, 原文作者:王猛猛;原文連結:http://server.it168.com/a2023/0221/6790/000006790356.shtml,如有侵權,請聯絡管理員刪除。

相關文章