iBox-面向Flutter的一站式研發(fā)工作臺(tái)
作者 | 蘇策
來(lái)源 | 阿里技術(shù)公眾號(hào)
一 前言
Flutter 一碼多端的特性,解放了端上同學(xué)的人力,帶來(lái)了研發(fā)效率的提升,淘特技術(shù)團(tuán)隊(duì)因?yàn)樵缙陔p端研發(fā)同學(xué)數(shù)量不匹配以及對(duì)研發(fā)效率的訴求,也是阿里集團(tuán)內(nèi)部比較早在業(yè)務(wù)上落地 Flutter 的團(tuán)隊(duì)之一。
雖然有了一碼多端的便利,但是伴隨而來(lái)的還有研發(fā)鏈路中的各種問(wèn)題,例如研發(fā)環(huán)境搭建,雙端工程環(huán)境,集成發(fā)布流程繁瑣等等。為了深入了解開(kāi)發(fā)同學(xué)們的痛點(diǎn),我們?cè)趫F(tuán)隊(duì)內(nèi)部發(fā)起了一份問(wèn)卷調(diào)查。
我們針對(duì)研發(fā)幸福感指數(shù)以及研發(fā)鏈路中遇到的各種問(wèn)題進(jìn)行了調(diào)查。結(jié)果如下:
編輯搜圖
在研發(fā)幸福感指數(shù)的打分中平均得分是 3.38(5分制)。我們針對(duì)影響研發(fā)幸福感的問(wèn)題進(jìn)行了分析,篩選出了一些大家普遍認(rèn)為影響研發(fā)效率的問(wèn)題。其中排名最高的是研發(fā)環(huán)境+工程環(huán)境(Flutter相關(guān))的搭建,開(kāi)發(fā)調(diào)試(Flutter相關(guān))等問(wèn)題。
接下來(lái)我們就來(lái)看看這些問(wèn)題的具體痛點(diǎn),以及解決這些問(wèn)題的時(shí)候面臨的一些挑戰(zhàn)。
二 問(wèn)題與挑戰(zhàn)
1 問(wèn)題
在影響研發(fā)幸福感的問(wèn)題中,主要是以下三個(gè)方面的問(wèn)題比較突出。
1)研發(fā)環(huán)境問(wèn)題
研發(fā)環(huán)境配置是編碼的前置工作,它也會(huì)影響新人落地對(duì)團(tuán)隊(duì)研發(fā)體驗(yàn)的第一印象。由于 Flutter 涉及 Android 與 iOS 雙端的環(huán)境配置,導(dǎo)致不熟悉另一個(gè)端的同學(xué)配置起來(lái),十分麻煩,上手難度高。另外,F(xiàn)lutter 本地版本不一致,缺乏 Flutter 版本管理工具,文檔零散更新不及時(shí),這些都極大的耗費(fèi)了團(tuán)隊(duì)同學(xué)的精力。
2)工程環(huán)境問(wèn)題
解決了研發(fā)環(huán)境問(wèn)題,還需要解決工程環(huán)境問(wèn)題,雙端工程架構(gòu)復(fù)雜,不熟悉某個(gè)端的同學(xué)面對(duì)編譯問(wèn)題難以解決。甚至很多同學(xué)就直接放棄了配置另外一個(gè)端的工程,平時(shí)開(kāi)發(fā)只對(duì)著自己熟悉的端調(diào)試,違背了 Flutter 雙端開(kāi)發(fā)的理念。
點(diǎn)評(píng):從團(tuán)隊(duì)的調(diào)研采訪來(lái)看,一個(gè)新人同學(xué)搭建 Flutter 的研發(fā)環(huán)境和工程環(huán)境,先需要一天時(shí)間搭建好基礎(chǔ)環(huán)境,后面的兩三天時(shí)間折騰各種編譯問(wèn)題,特別是 iOS 的相關(guān)環(huán)境對(duì)于 Android 同學(xué)來(lái)說(shuō)想要完整跑起來(lái)十分費(fèi)力。
3)集成流程問(wèn)題
等到代碼開(kāi)發(fā)測(cè)試完成以后,集成步驟多,平臺(tái)間來(lái)回切換,集成流程割裂,沒(méi)有形成完整的 SOP。整個(gè)集成流程既費(fèi)時(shí)費(fèi)力,又容易引發(fā)質(zhì)量問(wèn)題。
點(diǎn)評(píng):現(xiàn)有的 Flutter 模塊集成流程分為六步:1 模塊分支代碼合并 -> 2 模塊生成新Tag版本 -> 3 主工程修改模塊版本號(hào) -> 4 主工程代碼合并 -> 5 主工程生成版本號(hào) -> 6 摩天輪提交正式包打包,步驟繁瑣,需要在 Aone、MTL 等平臺(tái)來(lái)回切換,而且手工操作各種版本號(hào),很容易引發(fā)線上質(zhì)量問(wèn)題。
2 挑戰(zhàn)
為了解決這些問(wèn)題,之前也有沉淀一些文檔和腳本,但是文檔有很多步驟、命令,弄錯(cuò)任何一個(gè)就可能導(dǎo)致環(huán)境搭建出錯(cuò),另外文檔有時(shí)候也沒(méi)有及時(shí)更新。
我們想如果能有一個(gè)桌面端 GUI 形式的研發(fā)工作臺(tái),研發(fā)同學(xué)日常研發(fā)遇到的各種問(wèn)題都可以在這上面解決,新來(lái)的同學(xué)也可以借助這個(gè)研發(fā)工作臺(tái)快速落地,那對(duì)研發(fā)的幸福感將是一個(gè)質(zhì)的提升。
于是我們便決定打造一款桌面端的研發(fā)工作臺(tái),在實(shí)現(xiàn)這個(gè)目標(biāo)的過(guò)程中我們也遇到了很多挑戰(zhàn)。
1)如何降低開(kāi)發(fā)同學(xué)的接入和使用成本
-
接入和使用成本。研發(fā)工作臺(tái)本來(lái)作為一款工具軟件,它本身如果再操作復(fù)雜,需要看各種文檔,那就背離了工具軟件簡(jiǎn)單易用的初衷,所以復(fù)雜操作一鍵化是做相關(guān)功能時(shí)必須做到的,例如軟件環(huán)境一鍵配置,工程環(huán)境一鍵配置,一鍵集成發(fā)布等,很多功能都是按照這個(gè)思路來(lái)做的。
-
兼容現(xiàn)有的研發(fā)環(huán)境和工程環(huán)境。除了新來(lái)的同學(xué),大部分開(kāi)發(fā)同學(xué)的電腦上已經(jīng)有了部分環(huán)境,如何與現(xiàn)有的環(huán)境共存,不改變開(kāi)發(fā)同學(xué)現(xiàn)有的使用習(xí)慣,也是我們重點(diǎn)考慮的問(wèn)題。
2)如何保障架構(gòu)設(shè)計(jì)的合理性
我們想把研發(fā)工作臺(tái)打造成一個(gè)人人都可以參與進(jìn)來(lái)共建的開(kāi)放平臺(tái),因?yàn)閭€(gè)人的時(shí)間是有限的,工作臺(tái)本身作為一個(gè)工具集的聚合,需要更多的同學(xué)參與進(jìn)來(lái),更多的 idea 落地,所以如何做好倉(cāng)庫(kù)權(quán)限控制以及設(shè)計(jì)一個(gè)好的插件化框架就顯得很重要。
3)新技術(shù)的落地,相關(guān)問(wèn)題需要自己探索解決。
在桌面端研發(fā)工作臺(tái)的開(kāi)發(fā)中,我們使用的是 Flutter Desktop 技術(shù)(至于原因,技術(shù)調(diào)研部分會(huì)講),國(guó)內(nèi)目前 Flutter Desktop 技術(shù)在生產(chǎn)環(huán)境落地的并不多,相關(guān)經(jīng)驗(yàn)還比較缺乏,遇到一些問(wèn)題的時(shí)候,需要自己去探索解決。
接下來(lái)我們就來(lái)看一看我們?yōu)榱私鉀Q這些問(wèn)題,在 iBox 上設(shè)計(jì)了哪些核心的功能,以及這些功能是如何解決這些問(wèn)題的。
三 技術(shù)全景
1 技術(shù)調(diào)研
業(yè)界的客戶端研發(fā)工作臺(tái)的發(fā)展現(xiàn)狀。如下所示:
-
業(yè)界:EasyBox,MBox 等工具。這些工具的核心一方面在于解決 Native 環(huán)境搭建,開(kāi)發(fā)效率低的問(wèn)題。另一方面深度封裝 Git、Cocoapods,統(tǒng)一開(kāi)發(fā)模式。
-
淘特:也有一些零散的腳本工具。但是整體上沒(méi)有解決研發(fā)環(huán)境配置,開(kāi)發(fā)調(diào)試,集成發(fā)布等問(wèn)題。
整體上看是一個(gè)客戶端研發(fā)工作臺(tái)落地的契機(jī),業(yè)界有團(tuán)隊(duì)在嘗試,淘特在 Flutter 研發(fā)鏈路也有痛點(diǎn)和需求。既然要進(jìn)行桌面端開(kāi)發(fā),選擇一個(gè)桌面端開(kāi)發(fā)框架就成了首先要考慮的事情,當(dāng)下比較流行的桌面端開(kāi)發(fā)框架主要有以下兩種:
-
面向前端的 Electron:使用 JavaScript、HTML 和 CSS 構(gòu)建桌面端應(yīng)用程序。
-
面向客戶端的 Flutter Desktop:使用 Flutter 構(gòu)建桌面端應(yīng)用程序。
通常我們?cè)谧黾夹g(shù)選型的時(shí)候會(huì)從問(wèn)題解決,團(tuán)隊(duì)現(xiàn)狀,技術(shù)領(lǐng)域,業(yè)務(wù)趨勢(shì)等幾個(gè)方面層層遞進(jìn)去思考。
-
問(wèn)題解決:Electron 和 Flutter Desktop 這兩套方案都能解決我們的問(wèn)題,雖然性能上有差異,但是這個(gè)不是我們最關(guān)注的點(diǎn)。
-
團(tuán)隊(duì)現(xiàn)狀:客戶端同學(xué)對(duì) Flutter 熟悉,客戶端同學(xué)的上手成本更低,不依賴其他端的人力。從這個(gè)角度來(lái)看,F(xiàn)lutter Desktop 會(huì)更好。
-
技術(shù)領(lǐng)域:Electron 和 Flutter Desktop 都在向前發(fā)展,F(xiàn)lutter 團(tuán)隊(duì)今年推出的 Flutter 2.10 將 Windows 平臺(tái)正式帶入穩(wěn)定版本的支持,今年也會(huì)陸續(xù)完成 Linux、MacOS 等平臺(tái)的穩(wěn)定版本的支持。
-
業(yè)務(wù)趨勢(shì):工作臺(tái)未來(lái)可能會(huì)向全平臺(tái)擴(kuò)展。例如在桌面端是一個(gè)研發(fā)工作臺(tái),在移動(dòng)端(Android&iOS)iBox 是一個(gè)應(yīng)用小工具集或者是一個(gè)類似于螞蟻伙伴的app,在 Web 端是一個(gè)數(shù)據(jù)看板。從這個(gè)角度講,F(xiàn)lutter Desktop 會(huì)更好。另外我們還想在工作臺(tái)上做 UI 等組件的展示,如果基于 Flutter 來(lái)做,那么就能做到所見(jiàn)即所得,這會(huì)是一個(gè)非常好的體驗(yàn),
基于以上思考,我們最終選擇了 Flutter Desktop。有了開(kāi)發(fā)框架,我們接著來(lái)看看 iBox 的架構(gòu)設(shè)計(jì)。
2 功能設(shè)計(jì)
iBox 的核心定位
編輯搜圖
iBox 是一款基于 Flutter Desktop 技術(shù)棧研發(fā)的一站式、多樣化、可定制的研發(fā)工作臺(tái)。提供從研發(fā)環(huán)境到集成發(fā)布全流程的研發(fā)支持。核心功能包含工作臺(tái)、研發(fā)環(huán)境、工程管理、引擎管理、社區(qū)生態(tài)、變更單管理與工具箱等。
iBox 在功能設(shè)計(jì)上分為工作臺(tái)、研發(fā)、發(fā)布、工具箱四大板塊。其中研發(fā)、發(fā)布、工具箱又各自包含了很多子模塊功能。
我們著重介紹一下工作臺(tái)、研發(fā)環(huán)境與工程管理、社區(qū)生態(tài)、變更單管理等核心功能,讓大家對(duì) iBox 的整體功能有一個(gè)基本認(rèn)識(shí)。
工作臺(tái)
提供了最近變更單,常用平臺(tái)快捷入口等功能,讓常用功能一鍵直達(dá)。另外工作臺(tái)還預(yù)留了技術(shù)展示 Banner 位的功能,可以展示一些團(tuán)隊(duì)內(nèi)外的優(yōu)秀技術(shù)產(chǎn)出。后續(xù)還考慮將值班提醒,集成提醒,發(fā)布提醒做在工作臺(tái)上。
編輯搜圖
研發(fā)環(huán)境與工程管理
研發(fā)環(huán)境 + 工程管理 解決的是如何快速進(jìn)入本地開(kāi)發(fā)的問(wèn)題,如果是新人進(jìn)入團(tuán)隊(duì)開(kāi)發(fā),從拿到電腦到進(jìn)入開(kāi)發(fā),一般需要經(jīng)歷研發(fā)環(huán)境配置和工程環(huán)境配置這兩個(gè)流程。
在這個(gè)過(guò)程中需要去各個(gè)地方翻閱文檔,按照文檔進(jìn)行操作,在操作的過(guò)程中,還經(jīng)常伴隨著文檔更新不及時(shí),操作報(bào)錯(cuò),出了錯(cuò)誤又得去 Google 或者問(wèn)身邊的同事,整個(gè)過(guò)程費(fèi)時(shí)又費(fèi)力。
而 iBox 的研發(fā)環(huán)境和工程管理者兩個(gè)功能模塊則通過(guò)操作一鍵化來(lái)解決上述的問(wèn)題。
首先是研發(fā)環(huán)境提供了 Flutter、Android、iOS 研發(fā)環(huán)境的檢查和一鍵配置的功能,讓不熟悉某個(gè)端的同學(xué)更加便捷的配置自己的研發(fā)環(huán)境,如下所示:
編輯搜圖
然后是工程管理提供了混合工程下 Flutter、Android、iOS 等殼工程環(huán)境環(huán)境檢測(cè),一鍵環(huán)境配置等功能,解決了環(huán)境配置復(fù)雜難以上手的問(wèn)題,如下所示:
編輯搜圖
工程環(huán)境的復(fù)雜性在于它涉及 Flutter、Android、iOS 三個(gè)端的編譯,編譯的過(guò)程還會(huì)因?yàn)楸镜丨h(huán)境的差異而有所不同,各種編譯報(bào)錯(cuò),使得開(kāi)發(fā)同學(xué)窮于應(yīng)付。iBox 將從環(huán)境到工程的各種錯(cuò)誤類型進(jìn)行了梳理,并將錯(cuò)誤信息展示出來(lái),如下所示:
編輯搜圖
不僅讓開(kāi)發(fā)同學(xué)知道自己的工程環(huán)境有什么問(wèn)題,還提供了對(duì)工程環(huán)境問(wèn)題的一鍵修復(fù),一鍵修復(fù)功能會(huì)先刪除緩存(flutter clean,刪除lock文件等),然后按照以下流程重新跑整個(gè)工程,確??梢孕迯?fù)工程環(huán)境,如下所示:
編輯搜圖
研發(fā)環(huán)境和工程管理這兩個(gè)功能模塊相互配合,真正解決了開(kāi)發(fā)同學(xué)環(huán)境配置難的問(wèn)題,同時(shí)它還打破了 Android 與 iOS 之間的門(mén)檻,讓不熟悉另外一個(gè)端的同學(xué)也能進(jìn)行這個(gè)端的調(diào)試和打包。
社區(qū)生態(tài)
集團(tuán)內(nèi)外針對(duì) Flutter 都貢獻(xiàn)了不少功能組件,但是并沒(méi)有一個(gè)統(tǒng)一的地方展示這些組件,導(dǎo)致開(kāi)發(fā)同學(xué)在需要用的時(shí)候,需要去 pub 庫(kù)里各種搜索。
而 iBox 的社區(qū)生態(tài)功能提供了 Flutter 社區(qū)(集團(tuán)內(nèi)外)引擎、UI 組件、路由、動(dòng)態(tài)化等各個(gè)方面的技術(shù)沉淀的展示,特別是 UI 組件,由于 iBox 本身就是基于 Flutter 開(kāi)發(fā)的,那么這些 UI 組件的 Dart 代碼可以直接在 iBox 上運(yùn)行展示和交互,這種所見(jiàn)即所得的體驗(yàn)是非常棒的,如下所示:
編輯搜圖
變更單管理
在以前的開(kāi)發(fā)流程中,F(xiàn)lutter 的研發(fā)流程是比較繁瑣的,而且這些流程需要開(kāi)發(fā)自己手工操作,如下所示:
-
開(kāi)始開(kāi)發(fā)
-
創(chuàng)建Android摩天輪變更單
-
創(chuàng)建iOS摩天輪變更單
-
拉取變更分支
-
修改Flutter主工程的模塊依賴代碼
-
關(guān)聯(lián)Aone需求
-
開(kāi)發(fā)中
-
Android打包
-
iOS打包
-
提交模塊代碼CR
-
本地源碼依賴修改
-
完成開(kāi)發(fā)
-
模塊分支代碼合并
-
模塊生成新Tag版本
-
主工程修改模塊版本號(hào)
-
主工程代碼合并
-
主工程生成版本號(hào)
-
摩天輪提交正式包打包
而 iBox 的變更單功能,可以幫助 Flutter 研發(fā)同學(xué)快捷的完成研發(fā)流程的各種操作,如下所示:
編輯搜圖
-
開(kāi)始開(kāi)發(fā):iBox 可以關(guān)聯(lián) Aone 需求一鍵創(chuàng)建變更單,同時(shí)創(chuàng)建新的變更分支,準(zhǔn)備好當(dāng)前變更所需的工程環(huán)境。
-
開(kāi)發(fā)中:一鍵打 Android & iOS 雙端包,一鍵提交變更倉(cāng)庫(kù)的 CR。
-
完成開(kāi)發(fā):一鍵提交集成,提交的過(guò)程中會(huì)自動(dòng)完成上述的集成步驟。
這些一鍵式的操作不僅很好的提升了 Flutter 研發(fā)的效率,也規(guī)范了Flutter 的分支管理、集成方式,避免個(gè)人隨意操作帶來(lái)的工程問(wèn)題。
以上便是 iBox 一期規(guī)劃和完成的功能,它從根本上解決了上面提到的團(tuán)隊(duì)研發(fā)鏈路存在的種種問(wèn)題,同時(shí)也感謝閑魚(yú)同學(xué)在集成發(fā)布這塊為我們提供的飛魚(yú)工作臺(tái)相關(guān)實(shí)踐參考。
3 架構(gòu)設(shè)計(jì)
iBox 在架構(gòu)設(shè)計(jì)上主要關(guān)注以下幾個(gè)問(wèn)題:
-
問(wèn)題1:iBox 作為一款具備一定規(guī)模的 GUI 軟件,如何方便且安全的組織各個(gè)功能模塊的代碼。
-
問(wèn)題2:iBox 既然要面向共建,如何保證 iBox 自身的開(kāi)發(fā)體驗(yàn)。
-
問(wèn)題3:iBox 如何在保證共建開(kāi)放的同時(shí)保證軟件整體的質(zhì)量和性能。
通過(guò)對(duì)以上幾個(gè)問(wèn)題的思考,我們對(duì) iBox 采取了縱向分層,橫向模塊化的設(shè)計(jì),具體說(shuō)來(lái):
-
問(wèn)題1:不同的功能進(jìn)行模塊化設(shè)計(jì),模塊源碼彼此獨(dú)立。這樣可以精細(xì)控制源碼倉(cāng)庫(kù)的權(quán)限,不同模塊之間的修改不會(huì)相互影響。
-
問(wèn)題2:基于 git repo 進(jìn)行多倉(cāng)庫(kù)管理。既可以使用 git 操作單個(gè)的倉(cāng)庫(kù),也可以使用 git repo 對(duì)多個(gè)倉(cāng)庫(kù)進(jìn)行代碼同步,代碼提交,代碼 Review 等操作,保障了 iBox 多倉(cāng)庫(kù)協(xié)同的開(kāi)發(fā)體驗(yàn)。
-
問(wèn)題3:
-
約定每個(gè)模塊的基本架構(gòu)設(shè)計(jì)。包括源碼組織方式、狀態(tài)管理方案等方面內(nèi)容,并通過(guò)靜態(tài)掃描來(lái)保障這些約定的落地。
-
限制三方庫(kù)的引用以及指定三方庫(kù)的版本(不使用^號(hào)來(lái)指定版本,例如:url_launcher: ^6.0.20)。^號(hào)指定的版本會(huì)導(dǎo)致后兩位版本會(huì)自動(dòng)升級(jí)(flutter upgrade 和 重新生成 pubspec.lock 文件的時(shí)候),導(dǎo)致打包的時(shí)候使用了一些意料之外的版本,引發(fā)質(zhì)量問(wèn)題(參考最近的 url_launcher 的 url_launcher_macos 自動(dòng)升級(jí)導(dǎo)致鏈接打不開(kāi)的問(wèn)題 issue1 issue2 )。
整體架構(gòu)大圖如下所示:
編輯搜圖
從上面的架構(gòu)圖可以看出輔助功能作為基礎(chǔ)模塊,為其他核心功能提供基礎(chǔ)能力。接下來(lái)我們按照從工程到模塊的順序分別講一下具體的設(shè)計(jì)方案:
-
首先是整體工程的設(shè)計(jì)。
-
然后是具體模塊的設(shè)計(jì)。
工程結(jié)構(gòu)
在整體工程上采用多倉(cāng)庫(kù)設(shè)計(jì),之所以使用這樣的設(shè)計(jì),是因?yàn)?iBox 會(huì)涉及跨團(tuán)隊(duì)開(kāi)發(fā),多倉(cāng)庫(kù)可以讓各個(gè)模塊的源碼彼此獨(dú)立,不同模塊之間不會(huì)相互干擾。
iBox 基于 git-repo 實(shí)現(xiàn)了多倉(cāng)庫(kù)的管理,倉(cāng)庫(kù)結(jié)構(gòu)如下所示:
編輯搜圖
ibox 作為主工程,ibox_common 作為基礎(chǔ)模塊,其他模塊都依賴于 ibox_common。開(kāi)發(fā) iBox 的同學(xué)只需要幾行簡(jiǎn)單的命令,就可以同步 iBox 的全部源碼工程。
然后在自己的模塊進(jìn)行開(kāi)發(fā)和代碼提交即可,彼此之間互不干擾。聊完了整體工程的設(shè)計(jì),我們?cè)賮?lái)看看各個(gè)模塊的設(shè)計(jì)。
模塊設(shè)計(jì)
每個(gè)模塊的核心功能在于處理UI交互與邏輯交互,不同于傳統(tǒng)客戶端的命令式 UI 框架,F(xiàn)lutter 采用的是聲明式 UI 框架,驅(qū)動(dòng) UI 發(fā)生變化的是狀態(tài)(State),如下所示:
編輯搜圖
圖片引用自 Start thinking declaratively
Flutter 里的狀態(tài)指的是在 Widget 之間或者內(nèi)部存儲(chǔ)和傳遞的數(shù)據(jù)或者信息,它可以分為短時(shí)狀態(tài)和應(yīng)用狀態(tài)兩種。
-
短時(shí)狀態(tài)(exphmeral state):也稱為用戶UI狀態(tài)或者局部狀態(tài),是一個(gè)完全獨(dú)立在 Widget 里的狀態(tài)。Widget 樹(shù)里的其他部分不需要訪問(wèn)這種狀態(tài),它也不需要使用狀態(tài)架構(gòu)架構(gòu)(ScopedModel,Redux)去管理這種狀態(tài),它只需要一個(gè) StatefulWidget 就可以了。
-
應(yīng)用狀態(tài)(app state):它是一個(gè)應(yīng)用之間多個(gè)部分共享的一個(gè)非短時(shí)狀態(tài),并且用戶在會(huì)話期間,保留這個(gè)狀態(tài)。
所以狀態(tài)管理是編寫(xiě) UI 和邏輯核心要面對(duì)的問(wèn)題,它也會(huì)影響我們組織源碼的方式,在 Flutter 狀態(tài)管理的官方文檔中,提供了 14 種狀態(tài)管理方案,我們著重討論官方比較推薦的前四種,至于其他的方案,感興趣的可以去查閱官方文檔。
-
setState
-
InheritedWidget
-
Provider
-
Riverpod
我們先來(lái)看原生的兩種狀態(tài)管理方式:
-
setState:通常用于處理 Widget 內(nèi)部的短時(shí)狀態(tài)。
-
InheritedWidget:setState 只能處理 Widget 內(nèi)部的短時(shí)狀態(tài),如果需要處理應(yīng)用狀態(tài),在 Widget 樹(shù)之間進(jìn)行通信,則需要用到 InheritedWidget,InheritedWidget 可以為其子孫節(jié)點(diǎn)提供數(shù)據(jù)和服務(wù)。
setState 在應(yīng)用場(chǎng)景上比較受限,InheritedWidget 對(duì)于開(kāi)發(fā)者來(lái)說(shuō)過(guò)于底層,使用起來(lái)比較復(fù)雜。既然官方的方案都有限制,我們?cè)賮?lái)看看社區(qū)提供的提供的比較推薦的方案。
-
Provider:它對(duì) InheritedWidget 組件進(jìn)行了封裝,使其更加易用,更易復(fù)用。
-
Riverpod:基于 Provider 改進(jìn)而來(lái),它是一個(gè)響應(yīng)式的狀態(tài)管理和依賴注入框架,編譯安全,支持 DevTools 調(diào)試,本身不依賴于 Flutter。
事實(shí)上,Provider 和 Riverpod 的作者都是 Remi Rousselet,Riverpod 這個(gè)名字是 Provider 的字母重新排序后得到的,它的推出主要是為了解決 Provider 的一些功能缺陷,如下所示:
編輯搜圖
基于以上的比較,我們最終選擇了 Riverpod 這一套方案,并由此設(shè)計(jì)了模塊的源碼結(jié)構(gòu),如下所示:
編輯搜圖
iBox 模塊源碼結(jié)構(gòu) |----------------------------------------------------------- |--- provider 基于 Riverpod 實(shí)現(xiàn)的 State 管理方式(官方推薦) |----- xxx.provider.dart provider |--- service 接口請(qǐng)求、數(shù)據(jù)處理相關(guān)實(shí)現(xiàn) |----- xxx.service.dart service|--- ui 頁(yè)面與組件 |----- xxx.screen.dart 頁(yè)面
一個(gè)常見(jiàn)的編寫(xiě) UI 邏輯的流程如下所示:
-
在 ui 部分編寫(xiě)頁(yè)面和組件。
-
在 service 里編寫(xiě)和數(shù)據(jù)相關(guān)的邏輯。
-
在 provider 里編寫(xiě)相關(guān) provider 類,它可以調(diào)用 service 里的功能。
-
在 ui 或者其他任何需要的位置引用 provider,操作相關(guān)邏輯。
這種方式實(shí)現(xiàn)了 UI 與邏輯的解耦和分離,UI 部分可以自由迭代,邏輯部分也實(shí)現(xiàn)了復(fù)用。
以上便是 iBox 的整體架構(gòu)設(shè)計(jì),相當(dāng)于是一個(gè)簡(jiǎn)化版的插件化方案,如何后續(xù)有更豐富的插件生態(tài)進(jìn)來(lái),我們會(huì)考慮上架一個(gè)類似于 VSCode 的插件市場(chǎng),不過(guò)目前對(duì)于我們來(lái)說(shuō),已經(jīng)夠用了。
插件化的設(shè)計(jì)使得可以自由組裝各個(gè)模塊,不同團(tuán)隊(duì)需要的模塊功能不一樣,我們推出了 app variant(變體)的功能。不同的 app variant(變體)擁有不同的 tab 欄配置,打包的時(shí)候就可以針對(duì)不團(tuán)的團(tuán)隊(duì)打出不同功能的包。
4 上線效果
iBox 在研發(fā)鏈路核心痛點(diǎn)上使用前后對(duì)比
編輯搜圖
iBox 用戶在使用一段時(shí)間以后,也給了不少不錯(cuò)的反饋。
“一鍵安裝還是非常好用的,幫開(kāi)發(fā)節(jié)省了不少時(shí)間。以前各個(gè)地方下載,安裝配置,還要解決版本沖突的問(wèn)題,浪費(fèi)不少時(shí)間?!?/span>“這次版本集成全走的iBox, 用著很爽?!?
“大幅簡(jiǎn)化了 Flutter 環(huán)境配置、集成繁瑣等問(wèn)題?!?
此外,iBox 還處在一個(gè)剛起步的階段,我們希望把它作為一款產(chǎn)品去迭代和運(yùn)營(yíng)。為此我們也為 iBox 設(shè)計(jì)了不同視角下的運(yùn)維指標(biāo),如下所示:
全局視角:整體數(shù)據(jù)
-
全站 PV
-
全站 UV
-
覆蓋的團(tuán)隊(duì)數(shù)
-
各個(gè)團(tuán)隊(duì)的用戶覆蓋率
-
訪問(wèn)量前10的用戶
-
訪問(wèn)量前10的頁(yè)面
用戶視角:不同團(tuán)隊(duì)/個(gè)人偏好的功能
-
團(tuán)隊(duì) -> 功能模塊 訪問(wèn)次數(shù)
-
個(gè)人 -> 功能模塊 訪問(wèn)次數(shù)
業(yè)務(wù)視角:做的比較好,受歡迎的功能
-
最熱功能模塊排名
運(yùn)維數(shù)據(jù)體系需要長(zhǎng)期建設(shè),它對(duì)我們后續(xù)的功能迭代和體驗(yàn)優(yōu)化有著重要的指導(dǎo)意義,開(kāi)發(fā)同學(xué)也是用戶,只憑著拍腦袋想出來(lái)的功能,不一定能獲得大家的認(rèn)可。
四 技術(shù)總結(jié)
在做 iBox 之前,對(duì)于 Flutter 做過(guò)一些原理上的探究,之前整理編寫(xiě)了《從架構(gòu)到源碼:一文了解Flutter渲染機(jī)制》一文,但是沒(méi)有好的機(jī)會(huì)應(yīng)用在生產(chǎn)實(shí)踐上。這次的 iBox 開(kāi)發(fā)之旅讓我收獲頗多,借著這個(gè)機(jī)會(huì),我們就來(lái)聊一聊 Flutter Desktop 技術(shù)在生產(chǎn)實(shí)踐上的應(yīng)用。
1 Flutter Desktop 的發(fā)展歷程
從2018年2月15日Flutter 團(tuán)隊(duì)發(fā)起的 flutter-desktop-embedding 項(xiàng)目到現(xiàn)在,已經(jīng)四年過(guò)去了,中間的過(guò)程也是起起伏伏,從最初的不支持生產(chǎn)環(huán)境,到如今 Flutter 2.10 發(fā)布,正式宣布支持 Windows 平臺(tái)生產(chǎn)環(huán)境 app 的開(kāi)發(fā),F(xiàn)lutter Desktop 的發(fā)展歷程如下所示:
-
2018.02.15, 在 flutter-desktop-embedding 項(xiàng)目里提交第一個(gè) initial commit。
-
2019.12.05,支持了 MacOS 平臺(tái)。
-
2020.07.08,Linux 平臺(tái)進(jìn)入 alpha 階段。
-
2020.09.24,Windows 平臺(tái)進(jìn)入 alpha 階段。
-
2021.03.05,F(xiàn)lutter 2 正式發(fā)布,F(xiàn)lutter 對(duì)桌面端的支持進(jìn)入穩(wěn)定版本的前期準(zhǔn)備階段。
-
2022.02.15,F(xiàn)lutter 2.10 發(fā)布,Windows 平臺(tái)率先進(jìn)入穩(wěn)定版本,可用于生產(chǎn)級(jí) app 的研發(fā),其他平臺(tái)也在積極準(zhǔn)備中。
在 2022 年,F(xiàn)lutter 團(tuán)隊(duì)計(jì)劃按照 Windows、Linux、MacOS 的順序逐個(gè)推進(jìn),將對(duì)主流桌面端平臺(tái)的支持帶入到 stable channel,最終實(shí)現(xiàn) Flutter "write once, run anywhere" 的愿景。
2 Flutter Desktop 的社區(qū)生態(tài)
和對(duì) Android 和 iOS 的支持一樣,F(xiàn)lutter 也實(shí)現(xiàn)了基于 Windows 等平臺(tái)的 Embedder,Embedder 的上層是 C++ Engine 和 Dart Framework,它自己負(fù)責(zé)翻譯和發(fā)送 Windows 等平臺(tái)的消息。整體架構(gòu)如下所示:
編輯搜圖
圖片引用自 Announcing Flutter for Windows
點(diǎn)評(píng):Linux、MacOS 等其他桌面端平臺(tái)也是類似的實(shí)現(xiàn)結(jié)構(gòu),更深入的細(xì)節(jié)可以參見(jiàn) platform 的實(shí)現(xiàn)。
移動(dòng)端應(yīng)用和桌面端的應(yīng)用相比既有相同之處,例如:
-
GPU 圖形加速
-
渲染系統(tǒng)
-
動(dòng)畫(huà)
-
主題
-
文本輸入
-
國(guó)際化
-
UI 組件
這也使得大部分現(xiàn)有的 Flutter 社區(qū)組件都可以在桌面端使用,但兩者也有不同之處,例如:
-
更大的屏幕尺寸
-
支持鼠標(biāo)/鍵盤(pán)輸入
-
輸入法
-
導(dǎo)航方式
-
可訪問(wèn)性
-
系統(tǒng)獨(dú)有的視覺(jué)樣式
-
與底層系統(tǒng)的交互
基于這些不同,F(xiàn)lutter 針對(duì)桌面端平臺(tái)也提供了針對(duì)性的支持,如下所示:
編輯搜圖
圖片引用自 Announcing Flutter for Windows
在 iBox 的開(kāi)發(fā)過(guò)程中,我們也使用了不少原生能力,這里針對(duì) Flutter Desktop 常用的一些社區(qū)組件做個(gè)總結(jié),如下所示:
編輯搜圖
現(xiàn)有的社區(qū)組件基本能滿足我們的開(kāi)發(fā)需求。
3 Flutter Desktop 的應(yīng)用場(chǎng)景
iBox 是對(duì) Flutter Desktop 技術(shù)的一次有意義的探索,它為我們的產(chǎn)品帶來(lái)了更多的可能性,擴(kuò)展了產(chǎn)品觸達(dá)的邊界。
那么,F(xiàn)lutter Desktop 適合哪些應(yīng)用場(chǎng)景呢?
-
企業(yè)內(nèi)部使用的工具類軟件,尤其是在團(tuán)隊(duì)人員不足的時(shí)候,想快速落地一些工具和功能。
-
企業(yè)的ToB應(yīng)用,例如收銀臺(tái),餓了么商家端等。
-
團(tuán)隊(duì)自身已經(jīng)有基于 Flutter 開(kāi)發(fā)的移動(dòng)端應(yīng)用,想把部分功能擴(kuò)展到桌面端。
任何技術(shù)都有長(zhǎng)短,F(xiàn)lutter Desktop 也有不適合的應(yīng)用場(chǎng)景,如下所示:
-
對(duì)桌面端原生能力依賴較大的應(yīng)用,因?yàn)獒槍?duì)桌面端的社區(qū)生態(tài)支持還還不如移動(dòng)端這么完善,遇到缺乏的能力,需要自己去從零開(kāi)始搭建。
當(dāng)然技術(shù)也是不斷發(fā)展的,當(dāng)前存在的問(wèn)題,也許在將來(lái)就被解決了。筆者對(duì) Flutter Desktop 技術(shù)的發(fā)展還是很有信心的。
五 結(jié)語(yǔ)
Flutter 一份代碼,在兼顧性能的同時(shí)上可以多端運(yùn)行,是它的優(yōu)勢(shì)所在,解放了端上的生產(chǎn)力。尤其是對(duì)于 iOS 和 Android 同學(xué)比例嚴(yán)重失調(diào)的團(tuán)隊(duì)來(lái)說(shuō),這無(wú)疑是一個(gè)福音。
但是如果不注重 Flutter 開(kāi)發(fā)周邊配套工具的建設(shè),從最開(kāi)始的環(huán)境搭建、開(kāi)發(fā)調(diào)試、再到集成發(fā)布沒(méi)有好的工具去支撐,就很容易就演變成了 “Flutter 從入門(mén)到放棄”。這是因?yàn)闃I(yè)務(wù)團(tuán)隊(duì)和技術(shù)團(tuán)隊(duì)的訴求是不一樣的,技術(shù)團(tuán)隊(duì)覺(jué)得解決 Flutter 各種問(wèn)題的過(guò)程就是一個(gè)學(xué)習(xí)的過(guò)程,但是業(yè)務(wù)團(tuán)隊(duì)業(yè)務(wù)壓力大,他們的第一訴求是快速開(kāi)發(fā),快速上線,如果周邊配套工具缺失,他們很有可能就會(huì)選擇放棄這個(gè)方案,這對(duì)于 Flutter 的推廣是十分不利的。
我們希望剛接觸 Flutter 的開(kāi)發(fā)同學(xué),他們的使用體驗(yàn)是平滑的,能一鍵完成的就一鍵完成,例如我們提出的“一小時(shí)完成 Flutter 環(huán)境搭建”、“一鍵配置/修復(fù)工程環(huán)境” 等等,這些理念也與 Flutter 團(tuán)隊(duì)最近發(fā)布的年度規(guī)劃中的“提升開(kāi)發(fā)者體驗(yàn)”不謀而合。
今年 2月10號(hào),F(xiàn)lutter 團(tuán)隊(duì)發(fā)布了他們 2022 年的年度戰(zhàn)略(Flutter 2022 Strategy)和路線 (Flutter 2022 Roadmap)。如下所示:
編輯搜圖
可以看到未來(lái)一年,F(xiàn)lutter 團(tuán)隊(duì)將開(kāi)發(fā)者體驗(yàn)提到了非常重要的位置,他們將從 Flutter 的各個(gè)層面去改善開(kāi)發(fā)者體驗(yàn),例如:
-
提升 DevTools 的易用性。
-
讓 API 的使用體驗(yàn)更加平滑,逐步棄用和刪除舊的 API。
-
修復(fù) Hot Reload 有些時(shí)候不生效的問(wèn)題。
-
讓入門(mén) Flutter 體驗(yàn)更加平滑,降低入門(mén)門(mén)檻。
上述提到的一些理念,例如 “讓入門(mén) Flutter 體驗(yàn)更加平滑,降低入門(mén)門(mén)檻”,和我們做 iBox 的初衷不謀而合。另外在 iBox 后續(xù)的規(guī)劃中,我們除了降低開(kāi)發(fā)同學(xué)的 Flutter 入門(mén)門(mén)檻,還希望降低新團(tuán)隊(duì)接入 Flutter 的成本。
現(xiàn)有的 Flutter 接入方案以混合工程方案 add Flutter to existing app 為主,這套官方提供的方案有著不小的接入、重構(gòu)以及維護(hù)的成本,而且這是一個(gè)重復(fù)踩坑的過(guò)程,很多相同的問(wèn)題會(huì)被不同的團(tuán)隊(duì)再次遇到,如果 iBox 可以提供一鍵接入的方案,那么將大大降低 Flutter 的接入和填坑成本,助力 Flutter 的推廣。
Flutter 團(tuán)隊(duì)在年度戰(zhàn)略(Flutter 2022 Strategy)中提到 “以用戶(指 Flutter 開(kāi)發(fā)者)為中心,其他一切都會(huì)隨之而來(lái)”。
We believe in "focus on the user and all else will follow". This manifests in our emphasis on developer experience. 引用自 Flutter 2022 Strategy
相信在新的一年,F(xiàn)lutter 的研發(fā)體驗(yàn)會(huì)越來(lái)越好,iBox 也能為 Flutter 的推廣盡一份綿薄之力。
ALL in one:如何搭建端到端可觀測(cè)體系