Flutter 一码多端的特性,解放了端上同学的人力,带来了研发效率的提升,淘特技术团队因为早期双端研发同学数量不匹配以及对研发效率的诉求,也是阿里集团内部比较早在业务上落地 Flutter 的团队之一。
虽然有了一码多端的便利,但是伴随而来的还有研发链路中的各种问题,例如研发环境搭建,双端工程环境,集成发布流程繁琐等等。为了深入了解开发同学们的痛点,我们在团队内部发起了一份问卷调查。
我们针对研发幸福感指数以及研发链路中遇到的各种问题进行了调查。结果如下:
在研发幸福感指数的打分中平均得分是 3.38(5分制)。我们针对影响研发幸福感的问题进行了分析,筛选出了一些大家普遍认为影响研发效率的问题。其中排名最高的是研发环境+工程环境(Flutter相关)的搭建,开发调试(Flutter相关)等问题。
接下来我们就来看看这些问题的具体痛点,以及解决这些问题的时候面临的一些挑战。
在影响研发幸福感的问题中,主要是以下三个方面的问题比较突出。
1)研发环境问题
研发环境配置是编码的前置工作,它也会影响新人落地对团队研发体验的第一印象。由于 Flutter 涉及 Android 与 iOS 双端的环境配置,导致不熟悉另一个端的同学配置起来,十分麻烦,上手难度高。另外,Flutter 本地版本不一致,缺乏 Flutter 版本管理工具,文档零散更新不及时,这些都极大的耗费了团队同学的精力。
2)工程环境问题
解决了研发环境问题,还需要解决工程环境问题,双端工程架构复杂,不熟悉某个端的同学面对编译问题难以解决。甚至很多同学就直接放弃了配置另外一个端的工程,平时开发只对着自己熟悉的端调试,违背了 Flutter 双端开发的理念。
点评:从团队的调研采访来看,一个新人同学搭建 Flutter 的研发环境和工程环境,先需要一天时间搭建好基础环境,后面的两三天时间折腾各种编译问题,特别是 iOS 的相关环境对于 Android 同学来说想要完整跑起来十分费力。
3)集成流程问题
等到代码开发测试完成以后,集成步骤多,平台间来回切换,集成流程割裂,没有形成完整的 SOP。整个集成流程既费时费力,又容易引发质量问题。
点评:现有的 Flutter 模块集成流程分为六步:1 模块分支代码合并 -> 2 模块生成新Tag版本 -> 3 主工程修改模块版本号 -> 4 主工程代码合并 -> 5 主工程生成版本号 -> 6 摩天轮提交正式包打包,步骤繁琐,需要在 Aone、MTL 等平台来回切换,而且手工操作各种版本号,很容易引发线上质量问题。
为了解决这些问题,之前也有沉淀一些文档和脚本,但是文档有很多步骤、命令,弄错任何一个就可能导致环境搭建出错,另外文档有时候也没有及时更新。
我们想如果能有一个桌面端 GUI 形式的研发工作台,研发同学日常研发遇到的各种问题都可以在这上面解决,新来的同学也可以借助这个研发工作台快速落地,那对研发的幸福感将是一个质的提升。
于是我们便决定打造一款桌面端的研发工作台,在实现这个目标的过程中我们也遇到了很多挑战。
1)如何降低开发同学的接入和使用成本
2)如何保障架构设计的合理性
我们想把研发工作台打造成一个人人都可以参与进来共建的开放平台,因为个人的时间是有限的,工作台本身作为一个工具集的聚合,需要更多的同学参与进来,更多的 idea 落地,所以如何做好仓库权限控制以及设计一个好的插件化框架就显得很重要。
3)新技术的落地,相关问题需要自己探索解决。
在桌面端研发工作台的开发中,我们使用的是 Flutter Desktop 技术(至于原因,技术调研部分会讲),国内目前 Flutter Desktop 技术在生产环境落地的并不多,相关经验还比较缺乏,遇到一些问题的时候,需要自己去探索解决。
接下来我们就来看一看我们为了解决这些问题,在 iBox 上设计了哪些核心的功能,以及这些功能是如何解决这些问题的。
业界的客户端研发工作台的发展现状。如下所示:- 业界:EasyBox,MBox 等工具。这些工具的核心一方面在于解决 Native 环境搭建,开发效率低的问题。另一方面深度封装 Git、Cocoapods,统一开发模式。
整体上看是一个客户端研发工作台落地的契机,业界有团队在尝试,淘特在 Flutter 研发链路也有痛点和需求。既然要进行桌面端开发,选择一个桌面端开发框架就成了首先要考虑的事情,当下比较流行的桌面端开发框架主要有以下两种:
面向前端的 Electron:使用 JavaScript、HTML 和 CSS 构建桌面端应用程序。
通常我们在做技术选型的时候会从问题解决,团队现状,技术领域,业务趋势等几个方面层层递进去思考。
问题解决:Electron 和 Flutter Desktop 这两套方案都能解决我们的问题,虽然性能上有差异,但是这个不是我们最关注的点。
团队现状:客户端同学对 Flutter 熟悉,客户端同学的上手成本更低,不依赖其他端的人力。从这个角度来看,Flutter Desktop 会更好。
技术领域:Electron 和 Flutter Desktop 都在向前发展,Flutter 团队今年推出的 Flutter 2.10 将 Windows 平台正式带入稳定版本的支持,今年也会陆续完成 Linux、MacOS 等平台的稳定版本的支持。
基于以上思考,我们最终选择了 Flutter Desktop。有了开发框架,我们接着来看看 iBox 的架构设计。
iBox 的核心定位
iBox 是一款基于 Flutter Desktop 技术栈研发的一站式、多样化、可定制的研发工作台。提供从研发环境到集成发布全流程的研发支持。核心功能包含工作台、研发环境、工程管理、引擎管理、社区生态、变更单管理与工具箱等。
iBox 在功能设计上分为工作台、研发、发布、工具箱四大板块。其中研发、发布、工具箱又各自包含了很多子模块功能。
我们着重介绍一下工作台、研发环境与工程管理、社区生态、变更单管理等核心功能,让大家对 iBox 的整体功能有一个基本认识。
提供了最近变更单,常用平台快捷入口等功能,让常用功能一键直达。另外工作台还预留了技术展示 Banner 位的功能,可以展示一些团队内外的优秀技术产出。后续还考虑将值班提醒,集成提醒,发布提醒做在工作台上。
研发环境 + 工程管理 解决的是如何快速进入本地开发的问题,如果是新人进入团队开发,从拿到电脑到进入开发,一般需要经历研发环境配置和工程环境配置这两个流程。
在这个过程中需要去各个地方翻阅文档,按照文档进行操作,在操作的过程中,还经常伴随着文档更新不及时,操作报错,出了错误又得去 Google 或者问身边的同事,整个过程费时又费力。
而 iBox 的研发环境和工程管理者两个功能模块则通过操作一键化来解决上述的问题。
首先是研发环境提供了 Flutter、Android、iOS 研发环境的检查和一键配置的功能,让不熟悉某个端的同学更加便捷的配置自己的研发环境,如下所示:
然后是工程管理提供了混合工程下 Flutter、Android、iOS 等壳工程环境环境检测,一键环境配置等功能,解决了环境配置复杂难以上手的问题,如下所示:
工程环境的复杂性在于它涉及 Flutter、Android、iOS 三个端的编译,编译的过程还会因为本地环境的差异而有所不同,各种编译报错,使得开发同学穷于应付。iBox 将从环境到工程的各种错误类型进行了梳理,并将错误信息展示出来,如下所示:
不仅让开发同学知道自己的工程环境有什么问题,还提供了对工程环境问题的一键修复,一键修复功能会先删除缓存(flutter clean,删除lock文件等),然后按照以下流程重新跑整个工程,确保可以修复工程环境,如下所示:
研发环境和工程管理这两个功能模块相互配合,真正解决了开发同学环境配置难的问题,同时它还打破了 Android 与 iOS 之间的门槛,让不熟悉另外一个端的同学也能进行这个端的调试和打包。
集团内外针对 Flutter 都贡献了不少功能组件,但是并没有一个统一的地方展示这些组件,导致开发同学在需要用的时候,需要去 pub 库里各种搜索。
而 iBox 的社区生态功能提供了 Flutter 社区(集团内外)引擎、UI 组件、路由、动态化等各个方面的技术沉淀的展示,特别是 UI 组件,由于 iBox 本身就是基于 Flutter 开发的,那么这些 UI 组件的 Dart 代码可以直接在 iBox 上运行展示和交互,这种所见即所得的体验是非常棒的,如下所示:
在以前的开发流程中,Flutter 的研发流程是比较繁琐的,而且这些流程需要开发自己手工操作,如下所示:- 开始开发
创建iOS摩天轮变更单
修改Flutter主工程的模块依赖代码
关联Aone需求
开发中
iOS打包
本地源码依赖修改
完成开发
模块生成新Tag版本
主工程代码合并
而 iBox 的变更单功能,可以帮助 Flutter 研发同学快捷的完成研发流程的各种操作,如下所示:
开始开发:iBox 可以关联 Aone 需求一键创建变更单,同时创建新的变更分支,准备好当前变更所需的工程环境。
开发中:一键打 Android & iOS 双端包,一键提交变更仓库的 CR。
这些一键式的操作不仅很好的提升了 Flutter 研发的效率,也规范了Flutter 的分支管理、集成方式,避免个人随意操作带来的工程问题。
以上便是 iBox 一期规划和完成的功能,它从根本上解决了上面提到的团队研发链路存在的种种问题,同时也感谢闲鱼同学在集成发布这块为我们提供的飞鱼工作台相关实践参考。
iBox 在架构设计上主要关注以下几个问题:
问题1:iBox 作为一款具备一定规模的 GUI 软件,如何方便且安全的组织各个功能模块的代码。
问题2:iBox 既然要面向共建,如何保证 iBox 自身的开发体验。
通过对以上几个问题的思考,我们对 iBox 采取了纵向分层,横向模块化的设计,具体说来:
问题1:不同的功能进行模块化设计,模块源码彼此独立。这样可以精细控制源码仓库的权限,不同模块之间的修改不会相互影响。
问题2:基于 git repo 进行多仓库管理。既可以使用 git 操作单个的仓库,也可以使用 git repo 对多个仓库进行代码同步,代码提交,代码 Review 等操作,保障了 iBox 多仓库协同的开发体验。
问题3:
约定每个模块的基本架构设计。包括源码组织方式、状态管理方案等方面内容,并通过静态扫描来保障这些约定的落地。
整体架构大图如下所示:
从上面的架构图可以看出辅助功能作为基础模块,为其他核心功能提供基础能力。接下来我们按照从工程到模块的顺序分别讲一下具体的设计方案:
在整体工程上采用多仓库设计,之所以使用这样的设计,是因为 iBox 会涉及跨团队开发,多仓库可以让各个模块的源码彼此独立,不同模块之间不会相互干扰。
iBox 基于 git-repo 实现了多仓库的管理,仓库结构如下所示:
open-ibox git group
|-----------------------------------------------------------
|--- ibox
|--- ibox_common 基础模块
|--- ibox_dashboard 工作台
|--- ====== 研发 =====
|--- ibox_software 研发环境
|--- ibox_project 工程管理
|--- ibox_engine 引擎管理
|--- ibox_community_ecology 社区生态
|--- ====== 发布 =====
|--- ibox-app-size 包大小
|--- ibox-change-order 变更单
|--- ===== 工具箱 =====
|--- ibox-toolkit 研发小工具
ibox 作为主工程,ibox_common 作为基础模块,其他模块都依赖于 ibox_common。开发 iBox 的同学只需要几行简单的命令,就可以同步 iBox 的全部源码工程。
mkdir open-ibox
cd open-box
git repo init -u http://xxx/open-ibox/manifest.git
git repo sync
git repo start --all master
然后在自己的模块进行开发和代码提交即可,彼此之间互不干扰。聊完了整体工程的设计,我们再来看看各个模块的设计。
每个模块的核心功能在于处理UI交互与逻辑交互,不同于传统客户端的命令式 UI 框架,Flutter 采用的是声明式 UI 框架,驱动 UI 发生变化的是状态(State),如下所示:
图片引用自 Start thinking declaratively
Flutter 里的状态指的是在 Widget 之间或者内部存储和传递的数据或者信息,它可以分为短时状态和应用状态两种。
短时状态(exphmeral state):也称为用户UI状态或者局部状态,是一个完全独立在 Widget 里的状态。Widget 树里的其他部分不需要访问这种状态,它也不需要使用状态架构架构(ScopedModel,Redux)去管理这种状态,它只需要一个 StatefulWidget 就可以了。
所以状态管理是编写 UI 和逻辑核心要面对的问题,它也会影响我们组织源码的方式,在 Flutter 状态管理的官方文档中,提供了 14 种状态管理方案,我们着重讨论官方比较推荐的前四种,至于其他的方案,感兴趣的可以去查阅官方文档。
InheritedWidget
我们先来看原生的两种状态管理方式:
setState:通常用于处理 Widget 内部的短时状态。
setState 在应用场景上比较受限,InheritedWidget 对于开发者来说过于底层,使用起来比较复杂。既然官方的方案都有限制,我们再来看看社区提供的提供的比较推荐的方案。
Provider:它对 InheritedWidget 组件进行了封装,使其更加易用,更易复用。
事实上,Provider 和 Riverpod 的作者都是 Remi Rousselet,Riverpod 这个名字是 Provider 的字母重新排序后得到的,它的推出主要是为了解决 Provider 的一些功能缺陷,如下所示:
功能 | Provider | Riverpod |
---|---|---|
是否编译安全 | 存在运行时异常ProviderNotFoundException | 编译时安全,在编译期间捕获错误,能编译就能正常运行。 |
是否对 provder 的编写和引用有限制 | 不支持同一类型的多个 provider | 支持同一类型的多个 provider,也可以在任何地方编写和引用 provider。 |
是否依赖 Flutter | 依赖于 Flutter 的 Widget。UI 代码和依赖注入耦合在一起。 | 不依赖 Flutter 的 Widget。可以独立的创建/共享/测试 provider,这也包括在可以在没有BuildContext的情况监听 provder。 |
基于以上的比较,我们最终选择了 Riverpod 这一套方案,并由此设计了模块的源码结构,如下所示:
iBox 模块源码结构
|-----------------------------------------------------------
|--- provider 基于 Riverpod 实现的 State 管理方式(官方推荐)
|----- xxx.provider.dart provider
|--- service 接口请求、数据处理相关实现
|----- xxx.service.dart service
|--- ui 页面与组件
|----- xxx.screen.dart 页面
一个常见的编写 UI 逻辑的流程如下所示:
这种方式实现了 UI 与逻辑的解耦和分离,UI 部分可以自由迭代,逻辑部分也实现了复用。
以上便是 iBox 的整体架构设计,相当于是一个简化版的插件化方案,如何后续有更丰富的插件生态进来,我们会考虑上架一个类似于 VSCode 的插件市场,不过目前对于我们来说,已经够用了。
插件化的设计使得可以自由组装各个模块,不同团队需要的模块功能不一样,我们推出了 app variant(变体)的功能。不同的 app variant(变体)拥有不同的 tab 栏配置,打包的时候就可以针对不团的团队打出不同功能的包。
iBox 在研发链路核心痛点上使用前后对比
研发痛点 | 使用前 | 使用后 |
---|---|---|
研发环境 + 工程环境 | 一般需要一天时间搭建好研发环境,后面的两三天时间折腾工程的各种编译问题。 | 实现了两个“一”,环境配置(Flutter)一小时完成,打包集成一键完成。 |
社区生态 | 组件比较分散,不知道有哪些组件可以使用,没有引导文档,也不知道该怎么使用。 | 在 iBox 上进行可视化展示,所见即所得,可进行交互操作,附带 Demo 代码,使用方法清晰明了。 |
引擎管理 | 全局引擎切换需要修改文件夹名或者 profile | UI 界面一键切换,本地引擎版本统一管理。 |
变更单 | 需要跨两个平台,执行六步操作才能完成,手工操作还可能引发线上质量问题。 | 实现了集成步骤的 N 到 1,一键提交 Android 和 iOS 的双端集成。 |
iBox 用户在使用一段时间以后,也给了不少不错的反馈。
“一键安装还是非常好用的,帮开发节省了不少时间。以前各个地方下载,安装配置,还要解决版本冲突的问题,浪费不少时间。” “这次版本集成全走的iBox, 用着很爽。” “大幅简化了 Flutter 环境配置、集成繁琐等问题。”
此外,iBox 还处在一个刚起步的阶段,我们希望把它作为一款产品去迭代和运营。为此我们也为 iBox 设计了不同视角下的运维指标,如下所示:
全局视角:整体数据
全站 UV
各个团队的用户覆盖率
用户视角:不同团队/个人偏好的功能
业务视角:做的比较好,受欢迎的功能
运维数据体系需要长期建设,它对我们后续的功能迭代和体验优化有着重要的指导意义,开发同学也是用户,只凭着拍脑袋想出来的功能,不一定能获得大家的认可。
在做 iBox 之前,对于 Flutter 做过一些原理上的探究,之前整理编写了[《从架构到源码:一文了解Flutter渲染机制》] 一文,但是没有好的机会应用在生产实践上。这次的 iBox 开发之旅让我收获颇多,借着这个机会,我们就来聊一聊 Flutter Desktop 技术在生产实践上的应用。
从2018年2月15日Flutter 团队发起的 flutter-desktop-embedding 项目到现在,已经四年过去了,中间的过程也是起起伏伏,从最初的不支持生产环境,到如今 Flutter 2.10 发布,正式宣布支持 Windows 平台生产环境 app 的开发,Flutter Desktop 的发展历程如下所示:
2018.02.15, 在 flutter-desktop-embedding 项目里提交第一个 initial commit。
2019.12.05,支持了 MacOS 平台。
2020.07.08,Linux 平台进入 alpha 阶段。
2020.09.24,Windows 平台进入 alpha 阶段。
2021.03.05,[Flutter 2] 正式发布,Flutter 对桌面端的支持进入稳定版本的前期准备阶段。
在 2022 年,Flutter 团队计划按照 Windows、Linux、MacOS 的顺序逐个推进,将对主流桌面端平台的支持带入到 stable channel,最终实现 Flutter "write once, run anywhere" 的愿景。
和对 Android 和 iOS 的支持一样,Flutter 也实现了基于 Windows 等平台的 Embedder,Embedder 的上层是 C++ Engine 和 Dart Framework,它自己负责翻译和发送 Windows 等平台的消息。整体架构如下所示:
图片引用自 Announcing Flutter for Windows
点评:Linux、MacOS 等其他桌面端平台也是类似的实现结构,更深入的细节可以参见 platform 的实现。
移动端应用和桌面端的应用相比既有相同之处,例如:- GPU 图形加速
渲染系统
主题
国际化
这也使得大部分现有的 Flutter 社区组件都可以在桌面端使用,但两者也有不同之处,例如:
支持鼠标/键盘输入
导航方式
系统独有的视觉样式
基于这些不同,Flutter 针对桌面端平台也提供了针对性的支持,如下所示:
图片引用自 Announcing Flutter for Windows
在 iBox 的开发过程中,我们也使用了不少原生能力,这里针对 Flutter Desktop 常用的一些社区组件做个总结,如下所示:
现有的社区组件基本能满足我们的开发需求。
iBox 是对 Flutter Desktop 技术的一次有意义的探索,它为我们的产品带来了更多的可能性,扩展了产品触达的边界。
那么,Flutter Desktop 适合哪些应用场景呢?
企业内部使用的工具类软件,尤其是在团队人员不足的时候,想快速落地一些工具和功能。
企业的ToB应用,例如收银台,饿了么商家端等。
任何技术都有长短,Flutter Desktop 也有不适合的应用场景,如下所示:
当然技术也是不断发展的,当前存在的问题,也许在将来就被解决了。笔者对 Flutter Desktop 技术的发展还是很有信心的。
Flutter 一份代码,在兼顾性能的同时上可以多端运行,是它的优势所在,解放了端上的生产力。尤其是对于 iOS 和 Android 同学比例严重失调的团队来说,这无疑是一个福音。
但是如果不注重 Flutter 开发周边配套工具的建设,从最开始的环境搭建、开发调试、再到集成发布没有好的工具去支撑,就很容易就演变成了 “Flutter 从入门到放弃”。这是因为业务团队和技术团队的诉求是不一样的,技术团队觉得解决 Flutter 各种问题的过程就是一个学习的过程,但是业务团队业务压力大,他们的第一诉求是快速开发,快速上线,如果周边配套工具缺失,他们很有可能就会选择放弃这个方案,这对于 Flutter 的推广是十分不利的。
我们希望刚接触 Flutter 的开发同学,他们的使用体验是平滑的,能一键完成的就一键完成,例如我们提出的“一小时完成 Flutter 环境搭建”、“一键配置/修复工程环境” 等等,这些理念也与 Flutter 团队最近发布的年度规划中的“提升开发者体验”不谋而合。
今年 2月10号,Flutter 团队发布了他们 2022 年的年度战略(Flutter 2022 Strategy)和路线 (Flutter 2022 Roadmap)。如下所示:
可以看到未来一年,Flutter 团队将开发者体验提到了非常重要的位置,他们将从 Flutter 的各个层面去改善开发者体验,例如:
提升 DevTools 的易用性。
让 API 的使用体验更加平滑,逐步弃用和删除旧的 API。
修复 Hot Reload 有些时候不生效的问题。
上述提到的一些理念,例如 “让入门 Flutter 体验更加平滑,降低入门门槛”,和我们做 iBox 的初衷不谋而合。另外在 iBox 后续的规划中,我们除了降低开发同学的 Flutter 入门门槛,还希望降低新团队接入 Flutter 的成本。
现有的 Flutter 接入方案以混合工程方案 add Flutter to existing app 为主,这套官方提供的方案有着不小的接入、重构以及维护的成本,而且这是一个重复踩坑的过程,很多相同的问题会被不同的团队再次遇到,如果 iBox 可以提供一键接入的方案,那么将大大降低 Flutter 的接入和填坑成本,助力 Flutter 的推广。
Flutter 团队在年度战略(Flutter 2022 Strategy)中提到 “以用户(指 Flutter 开发者)为中心,其他一切都会随之而来”。
We believe in "focus on the user and all else will follow". This manifests in our emphasis on developer experience. 引用自 Flutter 2022 Strategy
相信在新的一年,Flutter 的研发体验会越来越好,iBox 也能为 Flutter 的推广尽一份绵薄之力。
macOS Performance Comparison: Flutter Desktop vs. Electron:https://getstream.io/blog/flutter-desktop-vs-electron/
List of state management approaches:https://docs.flutter.dev/development/data-and-backend/state-mgmt/options
riverpod:https://riverpod.dev/
provider:https://pub.dev/packages/provider
flutter-desktop-embedding:https://github.com/google/flutter-desktop-embedding
Start thinking declaratively:https://docs.flutter.dev/development/data-and-backend/state-mgmt/declarative
git-repo:https://git-repo.info/zh\_cn/docs/getting-started/installation/
Add Flutter to existing app:https://docs.flutter.dev/development/add-to-app
扫一扫
在手机上阅读