一、背景
笔者所在团队自2020年开始在项目中实践Flutter技术,Flutter先后承担了多个模块的开发与重构。在这个过程中针对Flutter项目如何在既有的原生工程中接入也走了一些弯路。
笔者最近接手Flutter整体的业务,开始梳理当前项目中的Flutter业务结构。借此机会梳理出来一份Flutter业务在我们项目的实践。
二、Flutter接入方案 1.0
在最开始的设计方案中由于Flutter负责的业务相对比较独立,因此采用了官方推荐的通用混合开发方案,通过Flutter Module进行add2app方式开发。业务中所涉及到的基础能力,如网络请求、数据存储,甚至部分提示控件(如弹窗、Toast等)通过调用原生现有的实现方案。在此后的一年中,进行了多次需求开发以及常规升级维护,一直运行比较稳定。
此后Flutter 团队再次负责了一个新业务的开发,经过当时研发同学反复权衡,采用了以下架构方案:
1、模块结构图
2、存在的问题
当业务B上线进入稳定运行状态后,此时研发团队开始思考当前存在不足之处,以及当前方案是否可以支持 Flutter 在项目中承载更多的业务开发。
经过反复思考发现了现有方案以下几个问题:
- 当前方案在面对多业务模式的混合开发架构设计上是不合理的。具体体现在项目中就是模块A中除了自身的业务代码之外,还承载了桥接原生和业务模块B的功能。尤其是路由分发、多语言适配、主题换肤等功能需要通过模块A进行分发处理。
- 如果后续有其他业务使用Flutter进行构建,那么这个业务依然需要挂载在模块A业务下。导致模块A业务内部与自身业务无关的代码越来越多,后期的维护上需要频繁的在模块A业务中对与其业务无关的代码进行修改,导致模块A原有的稳定性受到影响,后期的自测、交付测试都带来不必要的工作量以及重复性的工作。
- 由于模块A的所有核心代码都在Flutter Module中,而Module能承载的原生能力非常有限。导致原生项目为了支持Flutter业务的运行,需要提供大量的基础功能实现以及运行环境的配置代码,对于原生项目的入侵性比较强,也增加了Flutter开发人员对原生代码的维护工作量。
三、Flutter模块方案 2.0
基于以上思考,研发团队开始思考新的Flutter模块架构设计,经过探索与设计,最终探索出了下图所示的壳工程+业务模块+基础功能模块的工程结构。
1、新版结构图
2、各个模块介绍
shell_module
Module壳工程由于可以编译出原生接入的产物(Android aar、iOS xcFramework),适合负责对外的编译打包以及作为日程开发过程中的调试入口。 module中没有写任何代码,仅是调用了shell_plugin的main方法。
shell_plugin
Plugin壳工程由于工程中的Android和iOS文件夹内是一个完整的原生工程,可以在其中利用原生代码实现通用能力以及对Flutter业务的运行环境进行配置。这样可以大大简化原生项目的接入复杂度,并且对外屏蔽了内部实现细节,使得原生方面对Flutter接入和调用非常轻量化。同时Plugin壳工程承担了对内业务模块的组织和收敛。
- 在
pubspec.yaml
中 shell_plugin 依赖其他所有的plugin。 - 在 shell_plugin 中添加换肤、多语言等能力。
base_plugin
base_plugin 则是所有业务plugin的基础能力封装模块,类似Android工程中多个业务模块依赖的base_module。在1.0版本Flutter与服务端的交互能力全部通过原生代码来实现,里面虽然有一些历史包袱的原因,但这样Flutter整体对原生依赖变得更强,嵌入性较大,更加没有体现出来其作为跨平台开发的优势所在,所以在改版时,研发团队决定所有的能力均有Flutter自行构建,能够不依赖原生桥接的尽量不使用原生。
base_plugin 中大致封装了以下基础能力:
- Toast
- 网络
- 日志
- 图片加载
- SVG支持
- EventBus
- 列表刷新
- 各种widget组件
- 与Native交互的接口
- 各种通用 Mixin 能力
业务Plugin
各个业务Plugin作为业务模块依赖 base_plugin。其内部都是具体的业务逻辑了,这里就不多介绍了。
四、 总结
新版工程中存在的壳工程分为Module壳工程以及Plugin壳工程,通过Module壳工程和Plugin壳工程很好的承担了对外编译打包、对内收敛业务的重要任务。原因是充分利用了Flutter Module以及Flitter Plugin两种工程结构所能提供的能力。
由于结构的底层是基础的公共能力层,所以使得各业务模块之间没有依赖关系,对其中某个模块的维护不会影响其他模块的稳定性。在后期的交付环节可以节省QA同学的人力。 也正是因为模块之间的独立性,可以在Plugin壳工程中自由组合业务模块,可以方便地为原生应用提供不同业务能力组合的需求,为原生应用灵活赋能。
需要说明的是本篇的材料主要是来自我的同事大凡的一份文档,笔者针对其中涉及到具体业务的名词做了模糊处理,添加了一些自己的总结介绍。笔者是最近开始接手Flutter项目的,接手过来发现同事们在Flutter方向也走了很远,在这里对他们表示敬意。