Categories
程式開發

闲鱼Flutter实践与思考


Flutter 作为革命性的跨终端解决方案,于 2018 年 12 月正式发布,仅用了不到一年的时间就在 GitHub 和 StackOverflow 上获得了比 React Native 更高的知名度。那么所有项目都应该使用Flutter吗?并非如此。没有最好的框架,只有最适合的框架。是什么原因让闲鱼选择了 Flutter?闲鱼在架构 Flutter 化这方面有着怎样的经验与挑战呢?带着这些问题,InfoQ记者采访了GMTC专题出品人于佳(宗心),以下为采访实录。

迎接大前端时代

手淘客户端架构升级

我从14年开始参与手机淘宝的研发体系的升级,彼时正值淘宝all in无线的时期,大量研发人员涌入客户端进行开发工作。开发人员变多了,也带来了一个问题:当一百名以上的同学开出对应数量的分支进行研发时,在协同效率上出现了巨大的瓶颈,代码冲突十分严重,解决冲突的成本也着实难以承担。

手淘架构组临危受命,在没有任何业界先例的情况下,通过对比服务端的解决方案找到了工程拆分的解决方法——模块化。具体的方案是设计一个类似Spring IoC能力的轻量级容器,以保证各模块间的通信机制及接口调用标准。这样做的好处是:

各个模块通过接口的形式进行能力的对外暴露;

在集成阶段通过二进制包的方式保证了App整包的编译效率和各业务线的代码隔离。

这个方案极大的减少了集成的成本,也为后续手淘的快速迭代提供了保障,正因如此,这套基础架构的方案一直沿用至今。在前端急速发展的今天,端侧工程拆分也仍是大型客户端上常见的方法,同时对行业也有明显的借鉴意义。

天猫移动端架构合并

而淘宝和天猫的移动端架构合并则是手淘架构升级之后的事情了。有一天主管找到我并提出要基于手淘的新架构帮助手机天猫进行研发体系升级,进行一些底层能力的整合,诸如网关、H5容器等一系列端侧中间件标准。

如果说之前在手淘架构升级的过程中我的角色是执行者,那么这次的角色就有了很大的变化。一方面要修改代码,另一方面还要进行技术布道,同时还要说服一线开发和对方的主管,不单单是对技术与代码的执行者。外派的近一年时间中,我作为横向推动两个大的BU做架构整合的人,为了手机天猫的研发体系可以顺利升级,经历了很多不为人知的艰辛。虽然过程十分曲折,但结果是好的,最后我和同事一起完成了架构的合并。自此,手淘正式成为移动中台开始对集团输出能力。

闲鱼是在什么时候决定采用 Flutter 的?在此之前闲鱼 App 的客户端技术选型是怎样的?

2014年,集团内部孵化了闲鱼这个创业项目,次年我加入了闲鱼团队。当时的闲鱼人力非常有限,很多基本的用户体验问题都没有解决,因此闲鱼先推进了客户端基础设施全面拥抱淘宝的步伐,完成了移动中台底层中间件的对接以及配套基础设施的迁移。这样在极大降低了成本的同时也使闲鱼大幅度提升了性能和稳定性。此后的两年中,闲鱼团队的规模一直比较小,正因如此,我们一直在寻找提升研发效率的方案,并进行很多不同的尝试,后面会详细说明。

再经历了不同的尝试后,闲鱼选择了Flutter。而从“瞄”到Flutter到确定采用的这一过程,大概可以归为三个阶段:

1、2017年,闲鱼开始进行对Flutter的技术调研,思路是如何令小团队的研发效能大幅度提升。之后闲鱼又进行了前期的验证及与Google的合作;

2、2018年,开始进行实际的业务验证;

3、2019年,我们确认团队可以驾驭这项技术后,开始大规模落地与推进Flutter在闲鱼的应用。

目前闲鱼线上的主链路几乎已经完全拥抱Flutter,仅剩的一些业务也会在后续逐步进行迁移。

闲鱼的 Flutter 化架构演进之路

闲鱼在确定Flutter之前做过哪些尝试呢?首先来看当时的背景。

众所周知,在阿里的前端搭建体系里,Weex是主流方案,但当时闲鱼的产品主链路需要一个高性能、不降级的方案,该场景下这一类技术无法满足闲鱼客户端的需求。因此是否适合闲鱼客户端主链路使用成为了我们对技术方案的选择的主要考虑方向。

Native & Weex

首先我们想到了Native。起初我们尝试在Native双端都设计有同样概念的编程框架(OC/Java),统一端侧的代码标准,但落地的过程中发现两套代码及两个平台的差异很难避免。

然后闲鱼又尝试了集团的Weex作为主链路的方案。首先,闲鱼对主链路的稳定性要求较高,由于Weex的动态特性,线上只有一套代码,就有可能造成老版本的兼容性问题。在产品主链路,即使有千分之一的页面由于兼容性问题也会引起舆情问题,这是业务方无法接受的。其次,Weex的配套设施对客户端开发来讲存在一定成本。最后我们得出结论,Weex在导购体系和活动等场景下有比较好的性能提升且集团的配套设施比较完善,但可能不太适用于主链路的业务。

Flutter

在Native和Weex都不适用的情况下,闲鱼继续着探索之路,在持续探索的过程中,偶然间发现了Flutter这个方案。首先,从其设计理念来看,Flutter具有更好的多端一致性,优秀的性能,高效的研发配套工具,更贴近客户端的研发体系等等。从客户端的角度出发,我们觉得这就是主链路苦寻的方案。其次,Flutter背靠Google的同时又是开源产品,这点也给了我们信心。所以,闲鱼团队决定尝试Flutter。

RN

提到Flutter就自然会想到RN,对于RN来说,闲鱼团队在落地过程中并没有直接使用过。我认为RN和Weex比较像,整个研发体系包括工具链上面还是更偏向前端,Weex的主要优势是研发效率和动态性,在性能侧相比H5会有一些优势,因此比较适合代替现有的H5方案。而Flutter更偏向客户端的研发体系,研发效率和性能以及多端的强一致性是它的优势,基于这些优势,特别适合代替现有主链路的Native方案。

闲鱼 App 引入 Flutter 后,在效率、性能/体验和质量三个关键点上的表现如何?

效率

在引入Flutter前,开发间协同成本很高,导致协同效率低,例如双端开发分别需要与测试协同,双端开发之间需要协同等等,这样就导致协同成本过高。通过Flutter的落地,协同效率至少提升一倍。在目前的闲鱼大部分需求都是一个客户端同学独立完成的,研发侧在效率部分目前有将近80%左右的客户端代码是双端共享的,而且比例还在提升。

性能 & 体验

在早期我们做过一个实验,在低端机上,Flutter开发的新详情的性能是优于老详情的性能的。由于对绘制侧的统一优化以及对GPU的使用,让很多开发同学可以在复杂场景写出性能不错的代码。性能侧目前还有很多工作要做,由于Flutter的性能基线跟Native不太一样,在业内严谨的性能标准还没有出现。闲鱼团队最近还在与Google的同学沟通,看后续是否能一起定义Flutter侧性能的行业标准,并帮助完善部分Flutter社区的性能优化工具。

质量

质量侧iOS在内存消耗以及crash率上略高于Android,因此闲鱼在Engine侧做了一些优化和定制,阿里内部有比较严格的对crash率的标准,可以说目前看下来质量满足上线要求。

落地过程中有没有遇到一些挑战呢?闲鱼是如何解决这些挑战的呢?

闲鱼App引入Flutter后,在多方面都有了显著的提升,但落地过程并非一帆风顺,挑战一直伴随着整个落地过程。大致分为三个阶段:

第一个阶段主要的问题是行业内没有把Flutter放入已有工程体系进行开发的先例。

我们在这个过程中从工程架构、混合栈调用、打包构建、协同模式上都做了一些创新,保证了Flutter能融入已有闲鱼的客户端工程体系之内。后续我们推动了Google在milestone的变更,重点开始关注混合架构下的研发体验和配套设施,就是今天大家看到的闲鱼了。同时这个过程中我们沉淀出了现在团队在开源社区推出的混合栈框架Flutter_Boost。

第二个阶段主要的问题是性能和稳定性。

在初期几版灰度上线过程中,我们使用的是v0.5.6版本,当时还不是特别稳定,我们经常会因为crash以及一些诸如手势冲突相关的bug修改引擎并同步给Google的同学。另外,在中国特有环境下的适配问题,也需要我们对引擎依赖的一些三方库进行修改以适配各个厂商特有的ROM带来的bug。我们还发现音视频和图片的内存占用和CPU消耗上有不少问题,这个过程中我们也做了针对性的改进。

第三个阶段是Flutter大规模的推广的问题,真正意义上让团队每个同学都可以开发Flutter的代码。

而这一过程中,主要的挑战在于如何让没有经验的同学在短时间内可以写出高水平的Flutter代码并解决代码隔离问题。这部分我们通过对Redux的标准进行扩展,前后经历了三个版本的迭代讨论,最终在保持Redux核心三原则的基础上,扩展出了Component机制来解决组件复用以及代码隔离的问题,这个在多人协同的复杂业务上是非常重要的。我们也将其开源并命名为Fish-Redux,欢迎大家使用。

Flutter 的变化与展望

改进与优化

闲鱼在混合架构的演进的过程中,与Flutter相关的改动主要有两部分,第一部分是针对于引擎本身的Bug进行的修复工作,随着Flutter的日益完善,这部分目前对大家的参考意义不太大。

而另一部分则是关于性能的优化与改进。有两个比较典型的例子:

1、第一个是混合开发的开始阶段,如果每次都创建新的FlutterView进行渲染,会造成内存的严重消耗,但如果全局只使用一个FlutterView又会造成Native和Flutter页面栈管理复杂。基于这个问题我们研发出Flutter_Boost的方案,既保证了全局只有一个Engine实例共享,又通过该框架屏蔽了Native和Flutter页面栈管理复杂的问题。

2、另一个是针对图片和视频在Flutter页面上渲染的优化。主要的策略是通过改造Flutter Engine将绘制部分的API做扩展,允许Flutter Engine接受TextureID的直接传递,保证Flutter页面在使用外接纹理绘制的过程中整个调用链路足够短,使用的内存足够少。这个方案当然也有缺陷,就是需要改Engine,通过去年的优化,我们已经找到了类似缩短链路又不改引擎的方案,后续也会分享给大家。

后续规划

后续团队的Flutter发展规划大体有几个方面:

  • 目前需要基于闲鱼现有的技术体系,为集团赋能。我们正在跟淘宝架构团队进行横向的联通,通过贡献我们现有能力的方式,推进AliFlutter的落地,以帮助集团更多的团队。当然闲鱼主要是输出技术方案,中台本身还是由其他团队来支持和负责。

  • 闲鱼也有自己的主线,我们希望推进技术栈的归一,保证端和云的编程模型可以进行归一。举个例子,未来的业务团队一个人就可以从端到云进行开发,这对于构建柔性的技术组织有巨大好处,这种类型的组织极大的减少了技术栈之间的协同,对企业成本和效率有明显提升。

  • 我们也有非常多贴近业务的技术方案在进行尝试中。比如动态模版框架和轻量级游戏引擎,未来可能会产生一些机会和变化。

我们目前团队的架构师,Fish-Redux的作者吉丰将于今年的GMTC上给大家分享详细的架构设计和应用场景,欢迎大家参加。

您觉得 Flutter 在未来的发展趋势如何?跨平台开发会出现大一统的局面吗?

从目前的方案上来看,Flutter是行业内跨平台方案解决的较为彻底的一个,且背后有Google支持。大量的头部公司都有团队在持续投入和研究,因此我认为作为一种跨平台的解决方案,未来Flutter有机会成为主流的开发方式之一,另外由于它是跨终端的解决方案,未来在PC端和IoT设备端也会有一定的机会。

但Flutter一定不是唯一的方案,而且不可能完全代替Native开发。从成本和效率来说,若Flutter后续将生态完善起来,对于绝大部分小前台的App或需要多个终端进行投放的App来说将会是一个不错的选择,这也是大厂在推进Flutter上都比较积极的原因。对于大厂来讲,百花齐放是非常有必要的,大厂all in某一种技术是非常危险的选择。

而对于跨平台开发来说,行业内一直都在不断推陈出新,所以我觉得不太可能出现大一统局面。另外,跨平台开发框架其实是非常多的,除了Flutter,Weex和ReactNative,我们去看Qt,去看Cocos2d-x包括浏览器技术都是跨平台技术。技术选型跟团队架构师定义的当前问题、团队同学的知识结构、上下游的技术架构都有一定的关系,没有最好的技术,只有相应场景下具有优势的技术。

您观察到的大前端发展趋势是怎样的,对年轻化的前端、客户端开发人员来说应该怎样持续地学习成长?

除了传统的跨平台方案以外,端计算,AR/VR,5G下的音视频技术等等都是大家经常会提到的热点,这些讲起来有点虚了,我还是更多从一线的客户端开发人员的角度去看这个事情吧。

找到核心不变的部分

首先,端侧开发者永远都是最直接面向用户的,关注的重点主要集中在交互体验,渲染效果,端侧的性能等。但随着技术革新,新的设备与操作系统的出现,这几点可能会略有差异,但很多原理都是相通的。随着大前端入门门槛的降低,开发者若要保持竞争力,就需要在相应的领域里深耕,比如成为性能优化领域的专家,做一些别人无法做到的事情。

将已有技术改良优化

跨其他技术体系借鉴衍生了很多新的机会。比如端计算,除了现在大热的推理引擎以外,还有很多原来在服务端的技术方案可以转移到客户端。闲鱼团队目前在端侧就有实现轻量级的CEP引擎,或许不能像服务端CEP那么复杂,但是对于支撑实际的用户增长业务,完成实时的用户触达有比较好的效果。传统的App开发跟游戏技术的融合,也会产生一些新的想象力。

产生创新

拿Flutter来说,今天的混合开发上面遇到的问题,在Native和游戏框架融合的场景下也会出现,Flutter侧我们使用的外接纹理的方案,也是常见的混合渲染会使用的方案,所以是有很多共通之处的。因此当我们接触一个新的技术时,搞清楚底层原理,举一反三,定义出它的优势场景和问题并尝试通过其他类似领域遇到过的经验做优化,这种做法远好于学了一门新技术只做上层的开发,最后变为专业的UI还原工程师,要好的多。

保持好奇心,对技术追根问底的精神,日常多做总结养成好习惯,同时拓宽自己的技术视野,比如经常看看InfoQ的技术内容,看看别人是怎么做的,很重要。

嘉宾介绍

于佳,花名宗心,闲鱼技术团队客户端负责人。2012年应届毕业加入阿里巴巴,经历集团无线化转型的重要时期,参与过集团多款重量级App以及移动中间件的设计与开发,多年客户端老兵。2015年加入闲鱼客户端团队负责端架构和团队建设,工作期间完成了基于Flutter混合架构的闲鱼客户端的整体架构设计,在工程体系上完善了针对Flutter的持续集成以及高可用体系的支撑,同时推进了闲鱼主链路业务的Flutter化。