美团外卖Flutter动态化实践:纯Dart的挑战

发表时间: 2020-12-08 18:25

“一套代码,多端运行。”是很多开发团队的梦想,直到 2018 年 12 月 5 日,谷歌正式发布 Flutter 1.0 版本,前端开发者向这一梦想前进了一大步。Flutter 仅用了不到一年的时间就在 GitHub 和 StackOverflow 上获得了比 React Native 更高的知名度。Flutter 提供了一整套从底层渲染逻辑到上层开发语言的完整方案,有跨平台、高保真、高性能等优点。也正因为这些革命性的优点,从发布到现在,它的热度一路攀升,受到了很多开发者的热切青睐。目前各大公司的 Flutter 落地实现各有不同,此次 InfoQ 记者采访到了美团外卖的技术专家,Flap动态化项目的负责人董尚先,为我们分享了美团外卖采用 Flutter 的实践与经验。(相关视频分享已在线上录制完毕,预计在1月左右放出)

选择技术栈要看业务特点

美团外卖的用户端(下文用 C 端表示)和商家端(下文用 B 端表示)分别采用了不同的技术方案,原因是两端的业务特点不尽相同。二者均有美团标准化的 web 容器,但 C 端的用户量更大,对动态性要求更高,在低 pv 页面用 React Native 来做页面级的跨端动态化较多,在高 pv 页面使用美团外卖自研的区块级动态化和触达提示,最终支撑外卖 C 端的动态性业务需求。

相比之下,B 端的页面复杂度更高,C 端商品上的一些小标签,小按钮,在 B 端配置时有很深的层级和复杂的联动组件。此外,B 端需要关联到发配送,打印机等复杂逻辑,在实际开发时更加耗时。所以,B 端在技术选型时更看重跨平台框架的性能瓶颈与双端一致性。初期,美团外卖商家端也曾尝试过用 React Native 作为跨平台的技术方案,但过渡版本无法达到预期的要求,所以后期站队 Flutter 技术栈。

确定技术栈后的思考

Flutter 的“多端一致”和“渲染性能”上的优势让其他跨端方案很难比拟。虽然 Flutter 的成长曲线和未来前景看起来都很好,但不可否认的是,目前 Flutter 仍处在发展阶段,很多大型互联网企业都无法毫无顾虑地让全线 App 接入,而其中最主要的顾虑是包大小与动态化。

首先是包的体积问题,有很多大厂都做过 Flutter 的产物瘦身与包体积瘦身,美团也对此进行了尝试,最终优化后 Android 的包体积降低了 95% 左右,iOS 降低了 30% 左右。

其次是动态化,其实动态化与包体积之间是存在联系的:动态化可以带来动态性,从而可以动态下发 bundle,就可以间接地减少包的体积。目前尚未看到成熟且大范围落地的动态化方案。与此同时,美团外卖商家版的业务发展对动态化的诉求越发强烈,因此美团内部立项了 Flap 项目,目标就是支撑 Flutter 动态化能力。

为什么要用纯 Dart 的动态化方案

可能基于其他语言做动态化的惯性思考来看,相对方便点的实现是用 Dart 做视图 UI 部分,采用 JavaScript 处理逻辑,事件回调的时候用 callbackid 来标识, 这样的做法会带来很多限制:

  • 开发时要分开写;
  • 将存量的Flutter普通页面 迁移到 动态化 成本太大;
  • 运行时跨端通信损耗;
  • 并且视图和逻辑需要完全隔离的,视图中的逻辑部分很难处理。

美团 Flap 项目的基本目标是做一套完整的业务解决方案,支持大厂应用的复杂业务,而不是一些重展示轻交互或是 UI 与动态模板这样的方案。因此仅使用纯 Dart 语言去做,在不引入其他技术栈的情况下,攻克视图与逻辑一体化的动态化方案。这么做的好处基本就是上面列出的那些限制的反面:

  • 可以保持开发习惯与普通 Flutter 一致;
  • 写完后的代码可以在 Flutter 动态化和 Flutter 普通(AOT)上同时运行;
  • 并且在运行时没有跨端通信的损耗;
  • 最大的优点是可以迁移存量页面。Flutter 已经发展了一段时间,各个大厂都有大量的 Flutter 存量页面,使用常规方案迁移至动态化就需要重写代码,使用此方式可以接近 0 成本将其迁移至动态化,不用更换语言重新开发。

纯 Dart 所带来的挑战

Dart 是一种强类型、跨平台的客户端开发语言。具有专门为客户端优化、高生产力、快速高效、可移植(兼容 ARM/x86)和原生支持响应式编程(Stream & Future)等优秀特性。Dart 语言既有静态语言的特性,也支持部分动态语言的特性。

使用纯 Dart 的方式开发动态化的难点在视图逻辑一体化。相当于在 Dart 侧开发一个针对 Flutter 语言特性的解释器,需要对 Dart 整个语法特性有非常全面的认识。这里面的工作量也是很多的,我们在前期需要做很多的评估与拆解:

  • 需要在整体架构上区分 “准备符号”与“运行”两个阶段;
  • 需要考虑到视图和逻辑两个场景;
  • 需要考虑到系统类与自定义类的两种调用与加载方式;
  • 需要用一套合理的 bundle 管理机制做好相应的隔离与约束。

除此之外,还需要同步搭建支撑动态化的技术生态与工具,包括 IDE 语法检测插件(把问题前置到开发阶段)、代码生成工具、降级容灾系统等。对开发同学的技术储备要求较高。

业务落地只是目标之一,更重要的是在项目的实践过程中发现框架存在的问题,完善各类语法特性支持,提高在复杂的场景下的兼容性,促进框架的完善。在不断打磨中总结出合理的调试方案、操作步骤与协作方式,不断提升开发效率与体验。完善动态化基建及工具链建设,完成动态化流程的自动化与工程化,进一步降低转换与开发成本。

实际进展与开源计划

线上有些资料因为发布时间的问题,所以消息可能有滞后,现在已经 12 月上旬了,也快年底总结了,就以现在的口径为准吧。 目前外卖业务已经真实上线了 100+ Flap 页面,40+业务模块。目前外卖商家端的跨端与动态化覆盖度达到 90% 左右。 且已经在多个业务线实行需求动态发布流程,可动态上线的需求占比 60~80%,整体也是达到了年初时的预期。

至于开源应该到 21 年 Q2Q3。其实 sdk 很早就开发完了,之后是在通过业务落地来反哺 sdk 框架的打磨。 Flap 团队之所以没有第一时间开源,是因为觉得自己业务没广泛运用就开源是在“耍流氓”,后来我们也的确是优化了挺多问题。 下半年在能力和生态都建设的不错,一些边界的语法逻辑也都有了比较优雅的解决方案,接下来会在 Flutter 页面“零成本”转动态化的实施上再完善下,应该在 21 年 Q2Q3 左右开源。

Flutter 的使用体验与性能

在开发时,Flutter 这种累砖块的布局方式写起来“很爽”,客户端同学很好上手,大家反应写起代码来很快,在开发效率上已经有了不错的表现。

Flutter 的双端一直性做的很好,经常很多 Android 同学开发时拿 iOS 模拟器调试(因为 Android 调试一般都需要使用真机比较麻烦),iOS 模拟器开发完需求之后,拿 Android 设备再一跑大多都没问题。Native 基本就是提供好一些端能力的桥就 ok 了。性能方面,Flutter 和 Native 也很接近,没有 bug 的情况下,帧率也都是 59 朝上,渲染成功率也都是三个 9 以上。

在质量方面,目前外卖商家端的客户端 crash 和 Dart 异常是分开采集的。Flutter 大量覆盖之后 crash 占比中只有不到 10% 的量是由 Flutter 引起的,Dart 异常率不足千分之一。有时候上报的 Dart 异常并不会影响到用户的体验,例如有时候代码缺陷关了一个弹窗,报了一个异常,但弹窗依旧正常关闭了等等。

总的来说,使用 Flutter 后,在效率、质量、性能三个关键点上都达到了的预期,今年年底前,美团外卖商家端应该会将 Flutter 动态化覆盖至 80%以上。

跨平台开发更应该是百花齐放

从 2010 年 Android 伴随 Android 2.3 大火到 2013 年 iOS 伴随 iOS 7 进入大家的视野以来,客户端每年基本都有大新闻,2014 年 H5 的广泛应用让大量项目补充 Hybird 能力。 然后 2015、16 年 React Native 和 Weex 相继开源,大家先后投入到跨平台的开发。2017 年小程序和 PWA 先后登录,但 PWA 在 2018 年并没有达到人们期待的高度, 小程序则是稳扎稳打,移动端的流量也在逐步像小程序倾斜。但小程序的问题是巨头公司太多框架太多,谁都想做最大的平台,标准暂时统一不起来,还有一些路要走。 然后 2018 年 Flutter 1.0 出台,并且逐步有后来居上的优势,优点前面讲过了,在 GitHub 上的 star 数也是逐步超过了 Weex 和 React Native。

董尚先表示,目前 React Native 还是很强大,因为 React 互通的生态很多。但从长远目光来看,他觉得 Flutter 有成为商业 721 法则中的“7”的潜力。最大的特点 Flutter 是自渲染引擎,Flutter 的 embedder 层是非常轻薄的,同时也是目前跨端数量最多的,可以跨 6 端:

iOS / Android / Web / Linux / Mac / Windos 并且新系统 Fuchsia 也很大可能使用 Flutter 引擎 + Dart 语言。

目前许多大厂在同时使用多套跨平台方案,而不是单从某些标准抛弃其他择其一。未来一段时间内基本会过渡并维持到「内嵌 web 容器 + 少量 Native(端能力相关)+ Flutter / React Native 二选一+ 小程序」这样一个组合。

致客户端同学:学习跨平台技术栈

对于客户端同学,学习跨平台技术栈基本是现在 ROI 最高的事, 你需要结合自身业务的特点和自己公司的大环境,深度学习一门跨平台技术栈,可以是 Weex,可以是 Flutter,也可以是 React Native,然后先学明白一种,然后慢慢做到“一超多强”,其他的跨端也可以做到相对了解,写个 Demo 之类的。

关于学习方式,我建议最好系统的学习,你可以找一个风格适合自己的的 Flutter 专栏或博主把他的公众号的文章顺序读一遍。当然了,极客时间也是个很好的学习平台,里面也是有很多大牛会把一门课系统的教学一遍十几个课时,Flutter 在这里也有系统的学习课程,学习之后会有比较系统的技术储备以及对应的自信。

作者介绍

董尚先,美团技术专家。2015 年加入美团,经历了美团外卖的多个发展阶段,先后任职于用户端和商家端。曾主导外卖用户端架构升级、无人值守的自动化流程体系等项目。致力于提升研发效率,同时也是移动端领域新技术的爱好者,负责多项新技术在业务落地中的难点攻关,目前拥有 10 余项国家发明专利。现作为 Flutter 动态化项目的负责人,探索客户端 App 的最终形态。

延伸阅读:

Flutter包大小治理上的探索与实践-InfoQ

关注我并转发此篇文章,私信我“领取资料”,即可免费获得InfoQ价值4999元迷你书,点击文末「了解更多」,即可移步InfoQ官网,获取最新资讯~