QTalk 是去哪儿网内部的一个 IM 沟通工具,同时集成了很多内部的系统,比如 OA 审批,门禁打卡,请假审批,预定会议室,驼圈(驼厂朋友圈)等功能;方便内部办公沟通、交流的同时,也为无纸化办公,流程审批等提供了支持。
一、原有产品框架
在决定 Flutter 重构之前,我们盘点了现有的 QTalk 工程架构的问题,主要表现为:
各端差异性大 :Android、iOS 以及 QT 开发框架 (一个 C++桌面端跨平台解决方案) 三端逻辑代码差异大,代表性的有 Web 加载逻辑,移动端 React Native 页面加载逻辑等,排查问题根源时 3 端都会有不同的情况,解决方案也不相同。
研发效率低 :需要维护 3 套代码,在现有人力资源下,保证功能完整按时上线已经比较吃紧,还需要及时解决线上各种问题。
架构层次较差 :各端在架构设计上分层各不相同且不清晰,数据流推送方向复杂是主要的两个问题。
原生代码复杂度高 :蓝色区域代表了使用原生平台能力的代码,它们在各平台相互之间不可复用且容易在版本升级中出现适配问题,在实现需求的时候容易出现各端表现不一致返工的情况。
为了降低开发成本,提高开发效率,尽可能的将代码在各个平台进行复用,于是我们决定重构 QTalk。
二、为什么要选 Flutter
Flutter 的优势是渲染性能高与抹平了各端差异,根源在于 Flutter 采用了自主渲染引擎把控了渲染流程,保证了效率,相当于一个应用跑在了游戏引擎里。
以往就有人希望用 cocos2d 或者 unity 来制作应用,达到跨端一致与节省工时的目的,但是游戏引擎渲染是逐帧渲染,原生(iOS、Android)渲染方式是业务驱动,即有模型改动的情况下才渲染,相比之下游戏的渲染方式对性能消耗过大,包大小多倍增加,而 Flutter 通过对渲染流程的改造基本解决了这些问题,Flutter 在渲染时与原生渲染一样,都会产生渲染树,只有渲染树发生改变的时候,重绘制才会启动,而绘制一般也只发生在有改变的区域。
因 QTalk 开发资源紧缺,所以需要一个跨平台框架来提升效率。同时 QTalk 也是公司内平时沟通的主要方式,页面流畅性需要有保障。QTalk 常用的长短连接、长列表、Web 等,Flutter 官方和社区也有一个良好的支持。混合开发在 Flutter 2.0 中也得到官方引擎的支持,所以我们决定使用 Flutter 来开发新版 QTalk。
三、Flutter 版 QTalk 框架
可以看到,数据层来源于推送或 http 或者长连接,处理完成后变成 Flutter 中的 IMMessage 类型对象,在各个模块中处理数据库存储与交互逻辑层将数据处理完毕之后可以使用订阅者模式分发到各个界面使用,而上层的UI层使用Flutter进行开发,屏蔽了各层的差异,达到了最大。
相比于旧的架构,新的架构带来了如下的优势:
业务表现层基本抹平了各端差异,我们用一套代码实现了5端的UI ( Android、iOS、Mac、Windows、Linux), UI 整体代码复用率达到 80% 以上,避免了原有各端的表现差异带来的UI适配额外工作量。
逻辑与数据层除了个别能力(例如推送)必须使用原生代码,其余功能都 Dart 的统一实现,在维护和做新需求时工时减少约 50%。
在整个 APP 数据流动过程中,所有关于界面的数据都使用单向数据流,同时合理分层,降低了应用复杂度,所有组件都不需要保存状态,只负责根据数据源渲染。
四、遇到的问题
4.1 混合栈
QT 中大部分页面都是可以使用 Flutter 重构的 IM 业务页面,但是另外一些页面面临更新频繁,维护方不合适放在 IM 团队的问题,例如 QT 发现页,使用 ReactNative 开发,QT 只作为入口展示,所以我们需要一套混合 ReactNative 页面与 Flutter 的技术方案,现在 Flutter 的主流混合技术栈有 2 种:
Flutterboost 单引擎实现混合页面开发。
Flutter2.0 中官方发布的 FlutterEngineGroup 使用多引擎解决问题,优化了内存占用和数据共享方式。
我们在 QT 中对 2 种混合方式都进行了尝试,最终发现的它们各有利弊,如下表:
方案
Flutterboost
FlutterEngineGroup
优势
ioslate 共享内存,页面间数据传递方便
官方支持,代码侵入小,性能几乎不受影响