12月4日Flutter Live Beijing会议上,Google团队宣布第一个Flutter正式版本发布;并邀请了在这一技术方案中重要的合作伙伴闲鱼团队分享这半年以来的通过Flutter产出的业务结果以及对应的技术挑战。
本文根据Flutter Live Beijing嘉宾闲鱼客户端团队负责人于佳(宗心)的演讲内容进行整理,从Flutter的优势和挑战引出闲鱼这半年来针对Flutter基础设施进行重新的构建,定义,以及优化的过程,最后是这半年来对社区的一些贡献和未来的规划。
01 Flutter的优势与挑战
众所周知,Flutter提供了一套解决方案,既能用原生ARM代码直接调用的方式来加速图形渲染和UI绘制,又能同时运行在两大主流移动操作系统上,其像素级别的还原,保证了不同平台的UI强一致性。同时其提供了一整套机制(hot reload/attach Debug)保证开发的高效,基于此闲鱼团队在众多跨平台方案中选择了Flutter作为其未来主要的开发方案。
从4月份开始尝试在业务侧接入Flutter到现在,闲鱼在线上已经有10+的页面使用了Flutter进行开发,其中覆盖了核心主链路发布和详情。
闲鱼目前是市场上最大的闲置交易社区,作为一款有巨大用户体量的C端创新类产品,我们对体验以及研发迭代效率都有比较高的要求。在享受Flutter带来的收益的过程中,同样会面临技术转型过程中的一些挑战。主要的挑战来源于以下的三个方面
工程体系
在现有工程体系下如何将Flutter体系融入,并保持团队不同技术栈(Android/iOS/Flutter)的同学能各自独立高效进行开发。
业务架构
如何提供一套Flutter之上的业务架构,保证上层代码的统一标准,同时尽可能的使得代码的复用度及隔离性更好。
基础中间件
如何保证不同技术栈背后使用的基础能力是一致的(底层统一使用具有相同优化策略的图片库/音视频库),且在这个过程中如何解决Flutter融入后产生的问题。
面对这些挑战,闲鱼团队在下半年开始了针对基础设施的改造与重建。
02 基础设施重建之路
工程体系
工程体系部分,首当其冲需要考虑的是不同技术栈同学的协同问题,举例说明,我们的详情和发布页面是Flutter的,而首页以及搜索部分目前暂时采用native进行开发。这就需要考虑到Flutter的环境要对开发native的同学透明,甚至在native同学没有安装Flutter环境的情况下,依然可以保持原来的方式进行开发native页面。
如图中所示,以iOS为例,我们针对Flutter的框架Flutter.framewrok和业务代码App.framework通过持续集成服务进行打包并自动上传至云端的pod repo上,native同学只需在Podfile内指定对应的两个库的版本即可,同理,针对Flutter的plugin代码,同样打包上传至pod repo即可。
这套体系整体不复杂,需要说明的是,由于多人开发Flutter工程,因此打包是一件非常频繁的事情,因此我们这半年构建了持续集成体系来帮助大家将打包上传等整个体系做成一键式服务,另外,由于原有iOS平台的Flutter产物是需要依赖我们的native主工程的代码的,这种默认的打包方式,代码量巨大,造成持续集成时间在10-20分钟不等,因此在这个过程中,闲鱼团队通过直接基于xcodebackend.sh + insertdylib的自定义脚本完成了不依赖native主工程源码的打包,将持续集成时间降至2分半。同理在android上面,也进行了一些基础的改造,感兴趣的同学可以给我们留言,我们会根据大家的需求程度在后续安排贡献给Flutter社区。
另外一部分比较重要的内容是混合栈相关的,由于Flutter没有提供Flutter到混合工程的最佳实践,所以我们在上半年自建了一整套混合栈的体系,这里主要是分享一些混合栈的关键思考,在混合栈的实现过程中,需重点测试验证Dart这一侧widget的生命周期,并简化堆栈的管理(目前闲鱼的做法是将堆栈管理统一交由native进行控制,简化Dart层API),并需要考虑如何兼容Dart上层的比如Navigtor API的调用。整体这部分闲鱼团队还在验证当中,总之,这部分看似简单,但实际是比较深的坑,需要重点优化。另外,截至发文时间前,我们跟Google Flutter团队就混合栈交换了一些看法,Flutter团队后续如果可以提供多Flutterview,单Flutter engine的基础能力,就可以使得闲鱼现有的混合栈实现成本整体大幅度降低,后续大家有什么特别好的建议,也欢迎跟我们进行交流。
业务架构
今年下半年由于有更多的业务迁移至Flutter,这意味着更多的团队成员开始了Dart侧的研发。很快我们发现团队的代码风格,层次结构都比较混乱,bug也层出不穷,因此我们需要找到一种可以保证大家研发规范,同时确保多人协同过程中,代码既能更好的复用,又可以在适当的场景下做到相互隔离的这么一种方案。
在经过社区的多个框架库的实践和比较以后,不管是flex还是redux都不能完全解决我们的问题。最后我们选择了自己进行设计和实现,我们对框架进行基础分层以后,将重点最终落在了基于单一数据源的组件化框架上面,因此我们产生了自己的框架fishRedux,我们严格参考标准js的redux规范和源码(redux的设计三原则)进行了完整的Dart侧的实现,并在此基础上提供扩展能力用于我们的组件化开发。
如图所示,component将redux中的view,reducer,middleware以及我们的扩展能力effect进行组装,从而可以在不同的页面进行组件的复用,当然,全局依然遵循redux的单一数据源的原则,但我们将逻辑本身通过更细粒度的拆解,保证了这些逻辑在不同的component组装下都可以尽可能的进行复用。 基于这种结构,我们可以将任意的component进行挂载和拼装,通过更多小粒度的组件,产生不同场景下的复杂页面。
另外,针对于component的多层组装,大家可以细看下dependents这个字段,通过基于这个字段的组装,在我们提供的这段代码里面,实际上是提供了一个详情页面的插槽的功能,详情页面目前在闲鱼有近10种不同的组合,在这个场景下,可以在保证组件可以服用的同时,做到不同流程下的代码隔离。我们只要针对dependents的components里面进行替换,就可以很容易的达到在详情页面插入不同widget以及逻辑的效果。
fishRedux框架目前已经接近修改的尾声,目前还有部分微调和文档的补充,明年4月份前,我们有计划进行该框架的开源,为后续业务架构提供一个新的标准,大家敬请期待。
基础中间件
在阿里集团内部,已经产出了较多的基础中间件,因此如何复用这个中间件到Flutter侧是一个新的挑战,针对于传统的比如网络库,crash收集等中间件,由于不涉及到UI的复用,相对容易,但针对音视频,图片库等这类的中间件,虽然Flutter提供了FlutterTexture的方案,但依然不是特别完美。
我们在做音视频及图片库的复用过程中,主要的问题在于Flutter原生提供的机制,针对图片的渲染存在GPU到CPU,然后CPU再到GPU的这样一个过程,如图所示。根本原因在于不同的glContext无法共享texture。因此,我们目前采取的方案是修改Flutter引擎,并暴露出glContext的shareGroup(以iOS为例)。目前整个方案已经上线。
由于该改动目前在闲鱼自己fork的engine里面,因此目前将我们之前踩到的一些坑同步给大家,如果大家有在Flutter和native侧同时使用音视频的情况,建议特别注意ppt中的前两点,否则会造成Flutter侧或者native侧音视频的错乱。当然如果按照闲鱼团队的提供的修改方案进行engine改造后,也可以通过第三点,对native设置跟Flutter相同的sharegroup来解决这个问题。在Flutter live Beijing结束之后,我也将该方案正式介绍给Google Flutter团队,希望后续能将类似的功能融入Flutter的官方实现。
03 闲鱼与Flutter社区
闲鱼这半年,对于Flutter社区,也有一些小小的贡献。我们针对Flutter的方案进行整理并在各个技术社区进行传播。另外我们将已有的一些问题和解决方案提供给Google Flutter官方团队,直接或者间接的推动了Flutter的整体进度,并改变了这个技术未来的部分走向。我为自己的团队感到由衷的骄傲,但同时我意识到,要想让Flutter成为终端未来的主流技术,依然任重道远,因此我们后续也会将目前的一些相对稳定的框架和解决方案,逐步开源到社区,我们的要求是,至少闲鱼团队需要在线上有应用和验证。目前我们已经有一些初步的demo和小工具放在上面,大家感兴趣的可以往我们的github上提issue,我们后续会逐步开放更多的代码。最近会公布的比较重要的框架会是fishRedux,因此请大家持续关注我们。
04 总结与展望
我们首先带大家回顾了Flutter带来的优势以及在闲鱼的实际例子,并引出在复杂工程下的一些挑战。我们针对这些挑战,在下半年进行了整个体系的重新建设,初步完成了
隔离的混合工程体系
统一标准的业务架构
高效复用基础中间件设施
本次的分享,其实只是我们目前团队的一部分内容,我们基于Flutter和Dart还有更多的技术方案目前在预研和研发中,所以没有在这次live中进行宣讲。在后续跟Google Flutter团队的沟通中也了解到,他们对我们的多个方案都有较大的兴趣。对于未来来说,一方面,除了本文分享的内容以外,我们自己在代码自动生成/Dart Server/线上问题自动回放/国际化/动态模版等/持续集成等多个方面都在持续关注和调研。另一方面,在Flutter 1.0公布后,类似hummingbrid这一类全新的方案也有机会让Flutter具有全终端制霸的可能性,我们也会持续跟进和进行尝试。Anyway,依然希望有更多的同学可以加入我们一起完善Flutter的生态,同时通过新的技术手段,让天下没有闲置。来闲鱼一起改变世界吧,少年!