Flutter低代碼-Fair云開發(fā)平臺(tái)實(shí)踐

前言

Fair-Online 是面向Flutter 開發(fā)者,提供從Flutter 在線開發(fā),到實(shí)時(shí)編譯預(yù)覽,打包發(fā)布、動(dòng)態(tài)下發(fā)端側(cè)更新,實(shí)現(xiàn)Flutter 線上動(dòng)態(tài)化的一體化云開發(fā)平臺(tái)。開發(fā)者無需配置Flutter 開發(fā)環(huán)境,在線開發(fā)調(diào)試代碼,即時(shí)編譯預(yù)覽,所見即所得,結(jié)合58開源團(tuán)隊(duì)打造的Flutter 動(dòng)態(tài)化框架 Fair 及熱更新平臺(tái) FairPushy ,實(shí)現(xiàn)Flutter 線上動(dòng)態(tài)化。

目前Fair 云開發(fā)平臺(tái)已在Github 開源: Fair-Online Github 在線體驗(yàn)地址: Fair-Online Platform

Flutter 低代碼

熟悉Flutter 的小伙伴應(yīng)該都了解過 FlutterFlow ,它是目前比較完善的Flutter 低代碼平臺(tái),面向的是Flutter 零基礎(chǔ)開發(fā)者。開發(fā)者無需了解Flutter 的控件體系及語法規(guī)則,只需使用平臺(tái)提供的微件和復(fù)合組件,拖拽生成頁面即可。對(duì)于業(yè)務(wù)邏輯處理,比如網(wǎng)絡(luò)請(qǐng)求、事件Action處理等,是通過可視化的屬性編輯完成,平臺(tái)會(huì)根據(jù)開發(fā)者的操作生成對(duì)應(yīng)的Flutter 代碼。

在體驗(yàn)使用FlutterFlow 的過程中,我們也發(fā)現(xiàn)一些問題。首先,對(duì)于頁面UI開發(fā),如果要實(shí)現(xiàn)一個(gè)功能復(fù)雜,頁面層級(jí)較多的UI,使用拖拽組合,會(huì)變得非常繁瑣困難,這對(duì)Flutter 開發(fā)者是不夠友好的開發(fā)方式;其次,對(duì)于復(fù)雜業(yè)務(wù)邏輯的處理,比如網(wǎng)絡(luò)請(qǐng)求,事件Action處理等,使用可視化屬性設(shè)置,開發(fā)也比較繁瑣,且學(xué)習(xí)成本較高。

所以,針對(duì)上述問題,在技術(shù)選型上,區(qū)別于FlutterFlow 等低代碼平臺(tái)的拖拽編輯實(shí)現(xiàn),F(xiàn)air-Online 是面向Flutter 開發(fā)者,提供在線代碼編輯器,輔助以可視化的工程、頁面、組件創(chuàng)建、編輯,以實(shí)現(xiàn)Fair 開發(fā)提效,且?guī)缀鯖]有額外的學(xué)習(xí)成本。為了方便不熟悉Fair 的小伙伴快速上手Fair 開發(fā),平臺(tái)提供了常用的工程、組件模板以及網(wǎng)絡(luò)請(qǐng)求等業(yè)務(wù)邏輯,開發(fā)者在創(chuàng)建工程、頁面時(shí)可選擇模板創(chuàng)建,然后二次編輯。

Fair-Online 架構(gòu)

整體架構(gòu)設(shè)計(jì)分為前后端,都基于Dart 技術(shù)棧實(shí)現(xiàn)。 上半部分是前端,應(yīng)用展示層。技術(shù)棧使用的是Flutter Web + JS。

中間服務(wù)層

  • 包括 Code Editor(代碼編輯器)和 Preview(預(yù)覽)等組件。
  • Code Editor(代碼編輯器)是核心基礎(chǔ)功能。其中視圖部分使用CodeMirror , 它是一個(gè)使用JS實(shí)現(xiàn)的文本編輯器三方庫(kù);而邏輯部分,比如代碼分析、語法檢測(cè)、代碼補(bǔ)全等,使用Flutter 實(shí)現(xiàn)。
  • Preview(預(yù)覽功能),是基于Flutter 和Fair SDK 實(shí)現(xiàn)。

上層應(yīng)用層

  • 包括Flutter/Fair 的編譯運(yùn)行,F(xiàn)air 一鍵打包、代碼導(dǎo)出、手機(jī)掃碼預(yù)覽等;以及工程、頁面等編輯功能。

下半部分是后端,服務(wù)層,技術(shù)棧使用的是Dart Server。

中間服務(wù)層

  • 主要包括Fair SDK,F(xiàn)air 語法檢測(cè)插件。語法檢測(cè)是Fair-Online 的重點(diǎn)及實(shí)現(xiàn)難點(diǎn),后文會(huì)有詳細(xì)介紹。

上層應(yīng)用層

  • 主要包含用戶工程相關(guān),管理著用戶的工程、頁面、組件庫(kù)等。

下面詳細(xì)介紹下Fair-Online 中核心功能的實(shí)現(xiàn)。

在線代碼編輯器

Flutter在Web上運(yùn)行原理

Flutter Web 在Framework 層和移動(dòng)端Flutter 是相同的,區(qū)別在于渲染底層,移動(dòng)端通過內(nèi)置skia 引擎調(diào)用GPU 進(jìn)行繪制,而Flutter Web 則是將繪制引擎部分替換為標(biāo)準(zhǔn)HTML 標(biāo)簽以及Canvas 繪制的自定義標(biāo)簽,最終生成可繪制的dom 樹。

依托于dart compile 工具的 js模塊 (老版本為dart2js 工具),F(xiàn)lutter Web 的構(gòu)建工具可以將中間產(chǎn)物 app.dill 進(jìn)行讀取和解析,并注入 Math、List、Map 等 JS 工具方法,最終生產(chǎn)出Web 平臺(tái)所能執(zhí)行的JS 文件。

Flutter Web與JS的互操作性

Flutter 在移動(dòng)端的生態(tài)豐富,但是在Web 上面就差了很多,目前的Flutter Web 在開發(fā)中很大程度上依賴了Web 上豐富的三方庫(kù),所以能夠與JS 的函數(shù)互相調(diào)用是很重要的能力。

不同于Flutter 在移動(dòng)端上面與webview 的交互方式,由于Flutter Web 是運(yùn)行在瀏覽器環(huán)境中的,并且本身Dart 也會(huì)經(jīng)dart2js 轉(zhuǎn)化為JS 代碼,所以在Flutter Web 上面通過dart:js 或是packages:js 可以很輕松實(shí)現(xiàn)Dart 和JS 互相調(diào)用。

技術(shù)選型-CodeMirror

對(duì)于代碼編輯器的選擇上其實(shí)沒有什么挑選的空間,首先Flutter 技術(shù)棧的三方庫(kù)以移動(dòng)端為主,所以想要接入代碼編輯器這種組件,我們只能從JS 的技術(shù)棧上面選擇。CodeMirror 是一款在Web 上面老牌的代碼編輯器,功能強(qiáng)大,提供了十分豐富的API,并帶有多種語言模式和插件,可實(shí)現(xiàn)更高級(jí)的編輯功能,完全可以滿足我們的需求。

依賴Flutter Web 與JS 強(qiáng)大的互操作性,我們可以輕易地在集成CodeMirror,而Google 官方也提供了CodeMirror 的Dart 封裝庫(kù),其核心實(shí)現(xiàn)就是通過dart:js 庫(kù)對(duì)JS 側(cè)的CodeMirror 進(jìn)行API 的調(diào)用和交互 。

CodeMirror 作為Web 上面的UI 庫(kù)需要基于html 標(biāo)簽來展示,而在Flutter Web 中需要借助HtmlElementView 來往Widget 層次結(jié)構(gòu)中嵌入一個(gè) HTML 元素(在移動(dòng)端需要使用flutter_webview 插件),動(dòng)態(tài)構(gòu)建Html 標(biāo)簽需要在platformViewRegistry 注冊(cè)后使用。


/// 構(gòu)造用于承載CodeMirror的Html標(biāo)簽并注冊(cè)
final html.HtmlElement element = html.DivElement();
ui.platformViewRegistry.registerViewFactory(getCodeMirrorViewType(),
    (int viewId) {
  return element;
});

/// 初始化codemirror
editor = (editorFactory..paramsProvider = this)
    .createFromElement(element, options: codeMirrorOptions)
  ..theme = 'darkpad'
  ..mode = 'dart'
  ..showLineNumbers = true;

通過簡(jiǎn)單的初始化配置設(shè)定主題和語言模式后后,將HtmlElementView 嵌入Widget 層級(jí)中,就可以正常顯示代碼編輯器。

Fair-Online中代碼編輯器的前后端運(yùn)行原理

當(dāng)然如果要使代碼編輯器具備完善的功能,還少不了對(duì)代碼進(jìn)行語法檢測(cè)分析,通過快捷鍵觸發(fā)代碼的補(bǔ)全提示等功能,這些也是我們?nèi)粘i_發(fā)使用的AndroidStudio 和VSCode 中具備的必要功能。

CodeMirror 只是代碼編輯器的UI庫(kù),對(duì)于代碼語法的分析邏輯需要自定義,然后組裝分析結(jié)果交由CodeMirror 的Hint和Doc操作對(duì)象進(jìn)行實(shí)際的展示。在Fair-Online 的架構(gòu)中,F(xiàn)lutter 和Fair 的語法分析由Dart 編寫的服務(wù)端完成,具體的運(yùn)行原理如下圖所示:

  • 在Flutter Web 監(jiān)聽輸入和組合快捷鍵,觸發(fā)分析請(qǐng)求
  • Dart Server 通過Analysis Server 和Fair 語法分析插件生成分析結(jié)果,并返回給Web 端
  • Web 端通過將結(jié)果轉(zhuǎn)化為具體的操作對(duì)象,交由代碼編輯器來進(jìn)行文本操作或提示彈窗顯示
  • 通過Dart 和JS 的互操作性調(diào)用CodeMirror 的具體操作API

Flutter 語法分析

Analysis Server

Analysis Server 是官方提供的Dart 語法分析服務(wù),開發(fā)者熟悉的AndroidStudio、VSCode 等IDE 都是通過跟它的交互,完成語法靜態(tài)分析、代碼提示、代碼補(bǔ)全等功能。

以Android Studio 為例,語法檢測(cè)核心是Analysis Server,Dart 插件負(fù)責(zé)監(jiān)聽用戶代碼修改,每當(dāng)代碼有改動(dòng)時(shí),插件會(huì)通過Socket 同步給Analysis Server,Analysis Server 分析結(jié)束后將結(jié)果同步給Dart 插件,Dart插件根據(jù)Analysis Server 返回的事件類型進(jìn)行處理,最終通知Android Studio 刷新界面。詳細(xì)時(shí)序圖如下:

以上是IDE 中實(shí)現(xiàn)Flutter 語法檢測(cè)的過程。

自定義語法檢測(cè)

在Fair-Online 的代碼編輯器中,除了Flutter 語法分析,還需要支持自定義規(guī)則的語法分析檢測(cè),例如在布局與邏輯混編場(chǎng)景下,需要將代碼塊中的邏輯語句轉(zhuǎn)化為Fair 支持的語法糖。

對(duì)于自定義規(guī)則語法分析,我們可以通過自定義語法插件去實(shí)現(xiàn)。

語法插件的掛載問題。通過配置目標(biāo)工程的analysis_options.yaml 實(shí)現(xiàn)。Analysis Server 啟動(dòng)時(shí)會(huì)尋找這個(gè)配置文件,然后加載對(duì)應(yīng)的插件。

自定義語法檢測(cè)插件核心實(shí)現(xiàn)如下:

  • 輸入的是經(jīng)過處理后的編譯單元,里面包含由Dart 源代碼轉(zhuǎn)化而來的完整的抽象語法樹結(jié)構(gòu)。
  • FairVisitor 首先會(huì)遍歷抽象語法樹,檢查是否包含F(xiàn)airPatch 注解。因?yàn)橹挥邪現(xiàn)airPatch 注解的Flutter 代碼,才會(huì)被Fair 識(shí)別、編譯。
  • 接下來包含有FairPatch 注解的class 信息,交由FairClassVisitor 處理。
  • FairClassVistor 會(huì)遍歷class 中所有方法,根據(jù)方法類型分別交由特定的Visitor處理。每個(gè)Visitor 對(duì)應(yīng)的是一個(gè) Fair 語法糖。Visitor 之間是互相解耦的,后續(xù)可靈活擴(kuò)展。
  • 最后每個(gè)Visitor 遍歷方法體,進(jìn)行語法檢測(cè),分別返回語法分析的結(jié)果。

自定義語法檢測(cè)實(shí)現(xiàn)效果如下:

Flutter 在線編譯預(yù)覽

在我們使用Flutter 開發(fā)移動(dòng)端應(yīng)用時(shí),借助Debug 模式下的Hot Reload 功能可以實(shí)現(xiàn)在手機(jī)或模擬器上面快速的預(yù)覽代碼改動(dòng)。在傳統(tǒng)的低代碼平臺(tái)上因?yàn)椴捎猛献Э丶姆绞教烊坏闹С謱?duì)UI 效果的把控,而Fair 云開發(fā)平臺(tái)上面采用在線編寫代碼的方式,需要在網(wǎng)頁中快速預(yù)覽所寫代碼運(yùn)行后的效果。

Flutter Web上如何在線預(yù)覽代碼運(yùn)行效果

在代碼編輯器的部分中我們提到了Flutter 在Web 平臺(tái)上運(yùn)行的核心是dart2js,區(qū)別于移動(dòng)端,在Web 上 dart2js 通過將dart 編譯的中間產(chǎn)物dill 轉(zhuǎn)化為JS 來實(shí)現(xiàn)。

由于構(gòu)建Html 標(biāo)簽或者使用Canvas 來展現(xiàn)UI 的邏輯都在js中,按照這個(gè)思路我們可以將在線編寫的代碼通過 dart2js 編譯,然后嵌入Html 標(biāo)簽中進(jìn)行預(yù)覽。但如果處于同一window 和dom 下的話,資源和JS 環(huán)境會(huì)共享,會(huì)引起沖突,這時(shí)需要iframe 標(biāo)簽來解決這個(gè)問題。iframe 標(biāo)簽承載了一個(gè)單獨(dú)的嵌入的窗口,它有自己的 document 和window,所以大致思路就是將在線編輯的代碼轉(zhuǎn)化為JS 后注入一個(gè)iframe 內(nèi)進(jìn)行預(yù)覽。

Dartdevc編譯器

Dart 開發(fā)編譯器(dartdevc,也稱為DDC) 一般用于Flutter Web 開發(fā)時(shí)使用Chrome 運(yùn)行和調(diào)試。區(qū)別于 dart2js,dartdevc 支持增量編譯,所以在開發(fā)調(diào)試中可以做到類似移動(dòng)端Flutter 中HotReload的效果。dartdevc 通常需要配合webdev 一起使用,webdev 是使用Dart 開發(fā)和部署Web 應(yīng)用程序的命令行工具,比如監(jiān)聽文件變化觸發(fā)重建和重新部署就尤其負(fù)責(zé)。

Fair-Online編譯預(yù)覽前后端原理

出于對(duì)在線編譯速度的考量,F(xiàn)air云開發(fā)平臺(tái)在Dart 后端上面使用dartdevc 替代dart2js 進(jìn)行對(duì)代碼的編譯,生成的JS 產(chǎn)物返回前端注入到iframe 中進(jìn)行效果的預(yù)覽,具體實(shí)現(xiàn)流程如下圖所示:

  • 用戶在Fair云開發(fā)平臺(tái)在線編寫代碼
  • 前端通過用戶輸入發(fā)起編譯預(yù)覽請(qǐng)求
  • 后端接收請(qǐng)求,通過dartdevc 編譯器對(duì)工程代碼進(jìn)行編譯,將生成的JS 產(chǎn)物返回給前端
  • 前端將返回的JS 產(chǎn)物注入到iframe中進(jìn)行效果的預(yù)覽

支持我們

歡迎大家使用 Fair,也歡迎大家為我們點(diǎn)亮Star。

Github地址:github.com/wuba/fair

Fair官網(wǎng):fair.58.com

作者:58技術(shù)
鏈接:https://juejin.cn/post/7182537593001934909

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容