找回密码
 会员注册
查看: 35|回复: 0

转转Flutter实践之路

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
63703
发表于 2024-9-20 05:31:43 | 显示全部楼层 |阅读模式
前言跨端技术一直是移动端开发领域的热门话题,Flutter作为一种领先的移动跨端技术之一,凭借其快速的渲染引擎、丰富的UI组件库和强大的开发工具,成为了开发人员的首选之一。从Flutter诞生之初,我们就一直关注着它的发展,Flutter早期版本变更较为频繁,并且经常伴随着BreakingChange,另外可用的三方插件较少且不稳定。直到2019年,Flutter的热度暴涨,国内不少团队陆续把Flutter引入到了生产环境使用,社区也涌现出不少优秀的开源项目,我们也决定在这个时候做一些技术上的尝试。经过这几年在Flutter技术上的不断学习、探索和积累,Flutter已经成为了客户端技术体系中的重要组成部分。回顾整个过程,我们大致经历了这么几个阶段:可行性验证、基建一期建设、小范围试验、基建二期建设、大范围推广、前端生态的探索,下文将分别对每个阶段展开进行介绍。可行性验证其实在这之前我们已经做过了一些调研,但许多结论都是来源于网上的一些文章或者其它团队的实践,这些结论是否靠谱是否真实还有待商榷,另外,网上的文章大都千篇一律,要么使劲吹捧,要么使劲贬低,要得出相对客观的结论还是得需要我们自己通过实践才能得出。目标我们确定了以下几个维度,用来评估Flutter是否值得我们进一步投入:开发效率UI一致性性能体验学习成本发展趋势由于前期对Flutter的熟练度不高,基础设施也还没有搭建起来,所以在开发效率上,我们期望的Flutter的开发耗时能保持在原生开发耗时的1.5倍以内,不然虽然实现了跨端,但是需求的开发周期反而被拉长了,这样得不偿失。在UI一致性上,我们期望同一份代码在两端的表现要基本达到一致,不需要额外的适配成本。在性能方面,尽量保证崩溃、卡顿、内存、帧率这些指标在可控范围内。方案我们希望用较小的代价完成上述维度的评估,所以在试验期间的架构及基础设施方面我们做的比较简单。测试目标当时我们正在做一个叫切克的App,用户量级比较小,工程架构也相对简单一些,正好可以用来做一些技术方面的探索和验证。我们选择的是切克的商品页,用Flutter技术实现了一个一模一样的商详,按1:1的流量分配给Native和Flutter。项目架构由于我们的工程不是一个全新的项目,所以采用的是Native与Flutter混合开发的方式,Native主工程只依赖Flutter产物即可,同时也尽量避免对原有工程的影响。关于混合页面栈的问题,我们没有额外处理,因为暂时只测试一个页面,不会涉及到多页面混合栈的问题,所以暂时先忽略。构建流程为了降低验证成本,我们没有对接现有的Native的持续集成流程,而是直接在本地构建Flutter产物,然后上传到远程仓库。结论经过一段时间的线上验证,我对Flutter技术基本有了一个比较全面的了解:在开发效率上由于基础库和基建的缺失,在处理Flutter业务跟Native业务的交互时需要更多的适配成本,包括像页面跳转、埋点上报、接口请求、图片加载等也需要额外的处理,但我们评估随着后续基建的不断完善,这部分的效率是可以逐步得到改善的;而在涉及UI开发方面,得益于热重载等技术,Flutter的开发效率是要优于原生开发的。整体评估下来,在开发效率方面Flutter是符合我们的预期的。在UI一致性上,除了在状态栏控制和文本在某些情况下需要特殊适配下外,其它控件在两端的表现基本一致。在性能表现上,Flutter会额外引入一些崩溃,内存占用也有所上涨,但还在可接受范围内。Flutter的学习成本相对还是比较高,毕竟需要单独学习一门语言,另外Flutter的渲染原理也跟原生有很多差异,需要转变思维才能更快的适应,此外Flutter还提供了众多的Widget组件,也需要较长时间学习。在发展趋势上,Flutter无疑是当时增长最快的跨端技术之一,社区的活跃程度以及官方的投入都非常高,国内不少团队也都在积极推进Flutter技术的发展,Flutter正处在一个快速的上升期。整体来说,Flutter是满足我们团队对跨平台技术的需求的,我们计划在接下来的一段时间投入更多资源,把Flutter的基础设施逐渐建立起来。基建一期建设基建一期内容主要包括以下几个方面:工程架构开发框架脚本工具自动化构建在基建一期完成后,我们的目标是要达到:基础能力足够支撑普通业务开发开发效率接近原生开发开发过程要基本顺畅工程架构工程架构指的是原生工程与Flutter工程之间的关系,以及Flutter工程与Flutter工程之间的关系。原生工程与Flutter工程的关系我们知道,使用Flutter开发通常有两种情况,一种是直接使用Flutter开发一个新的App,属于纯Flutter开发;一种是在已有的Native工程中引入,属于混合开发。我们当然属于后者。而混合开发又可分为两种:源码集成和产物集成。源码集成需要改变原工程的项目结构,并且需要Flutter开发环境才能编译,而产物集成则不需要改动原工程的项目结构,只需把Flutter的构建产物当作普通的依赖库引入即可,原有Native工程和Flutter工程从物理上完全独立。显而易见的我们选择产物集成的方式,引入Flutter对于原工程以及非Flutter开发人员来说,基本上是毫无感知的。所以原生工程与Flutter工程之间的关系如下图所示:原生工程与Flutter工程之间的关系Flutter工程之间的关系根据已有的客户端基建的开发经验,我们将所有Flutter工程分为了四层:壳工程业务层公共层容器层容器层负责提供Flutter的基础运行环境,包括Flutter引擎管理、页面栈管理、网络框架、KV存储、数据库访问、埋点框架、Native与Flutter通信通道和其它基础功能。公共层包含一些通用的开源库、自定义UI组件、部分通用业务等。业务层包含用户信息、商品、发布等业务组件。壳工程负责集成各业务组件,最终构建出产物集成到Native主工程。其中业务层、公共层、容器层都是由若干个独立的工程所组成,整体结构如下:Flutter分层架构开发框架开发框架是为了提高开发效率、规范代码结构、减少维护成本等考虑而设计的一套软件框架,包括:基础能力、状态管理、页面栈管理等。基础能力开发框架需要提供各种必要的能力,比如:页面跳转、埋点、网络请求、图片加载、数据存储等,为了最大化减少研发成本,我们在底层定义了一套通用的数据交互协议,直接复用了现有的Native的各项能力,也使得Native的各种状态与Flutter侧能够保持统一。状态管理相信了解Flutter的同学一定知道状态管理,这也是跟Native开发区别较大的地方。在开发较为复杂的页面时,状态维护是非常繁琐的,在不引入状态管理框架的情况下,开发效率会受很大影响,后期的维护成本以及业务交接都是很大的问题。另外,在开发框架设计之初,我们就期望从框架上能够在一定程度上限定代码结构、模块之间的交互方式、状态更新方式等,我们期望的是不同的人写出来的代码在逻辑、结构和风格上都能保持比较统一,即在提高开发效率的同时,也能保证项目后续的可维护性和扩展性,减少不同业务间的交接成本。基于上述这些需求,在我们对比了多个开源项目后,FishRedux的整体使用感受正好符合我们的要求。如下图,两个页面的代码结构基本一致:收藏和个人主页页面栈管理在早期版本,Flutter引擎的实例占用内存较高,为了减少内存消耗,大家普遍采用单实例的模式,而在Native和Flutter混合开发的场景下就会存在一个问题,就是Native有自己的页面栈,而Flutter也维护着一套自己的页面栈,如果Native页面与Flutter页面穿插着打开,在没有特殊处理的情况下,页面栈会发生错乱。在调研了业内的各种开源方案后,我们选择引入FlutterBoost用来管理页面混合栈。脚本工具为了方便开发同学搭建Flutter的开发环境,同时能够管理使用的Flutter版本,我们开发了zflutter命令行工具,包含以下主要功能:Flutter开发环境安装Flutter版本管理创建模版工程(主工程、组件工程)创建模版页面(常规页面、列表页、瀑布流页面)创建页面模块组件工程发布构建Flutter产物脚本自更新如图:zflutter自动化构建客户端使用的是自研的Beetle平台(集工程管理、分支管理、编译、发布于一体),短时间内要支持上Flutter不太现实,基于此,我们先临时自己搭台服务器,通过gitlab的webhook功能结合zflutter工具简单实现了一套自动化构建的服务,待Beetle支持Flutter组件化开发功能后,再将工作流切回到Beetle平台。小范围试验在完成基建一期的开发工作后,我们决定通过开发几个实际业务来试验目前的基础设施是否达到既定目标。我们以不影响主流程、能覆盖常见UI功能、并且能跟Native页面做AB测试(主要是方便在出问题时能够切换到Native版本)为条件挑选了个人资料页和留言列表页进行了Flutter化改造,如下图所示:个人资料页/留言列表页这两个页面涵盖了网络请求、图片加载、弹窗、列表、下拉刷新、上拉加载更多、左滑删除、埋点上报、页面跳转等常见功能,足以覆盖日常开发所需的基础能力。经过完整的开发流程以及一段时间的线上观察,我们得出如下结论:基础能力目前已具备的基础能力已经足够支撑普通业务开发(开发过程中补足了一些缺失的能力)。工作流整个开发过程在工程依赖管理和分支管理方面的支持还比较缺失,比较依赖人工处理。开发效率我们在开发前根据页面功能同时做了纯Native开发排期和Flutter开发排期,按单人日的成本来对比的话,Flutter实际开发耗时跟Native排期耗时比为1.25:2,Native是按照Android+iOS两端各一人算的,也就是1.25人/日比2人/日,如果后续对Flutter技术熟悉度提升后相信效率还可以进一步提升。性能体验线上两个Flutter页面的体验效果跟Native对比基本感觉不到差别,但是首次进入Flutter页面时会有短暂的白屏等待时间,这个是由于Flutter环境初始化导致的延迟,后续可以想办法优化。包体积在引入Flutter之后,转转的安装包体积在两端都分别有所增加:Android增加6.1MiOS增加14M试验结果基本符合预期,包体积的增量也在我们的可接受范围内,接下来将进行基建二期的建设,补足目前缺失的能力。基建二期建设基建二期的内容主要包含以下工作:配合工程效率组完成Beetle对Flutter项目的支持组织客户端内部进行Flutter技术培训Beetle支持Flutter为了能让大家更清晰的了解Beetle的工程管理机制,这里先简单介绍下客户端的工程类型:Native主工程(又分为Android和iOS)Native组件工程(又分为Android和iOS)Flutter主工程Flutter组件工程(即Flutter插件工程)举个例子,当有一个新版本需要开发时,先从Native主工程创建一个版本同时创建一个Release分支,即版本分支,然后从版本分支根据具体需求创建对应Native组件的版本分支,Flutter主工程此时可看作是一个Native组件,比如此时创建了一个Flutter主工程的版本分支后,可以进入Flutter主工程再根据需要创建对应的Flutter组件工程的版本分支。Beetle目前已支持Flutter工程管理、分支管理、组件依赖管理以及组件的发布、Flutter产物的构建等,Beetle的作用贯穿从开发到上线的整个工作流。Flutter技术培训为了让大家更快的熟悉Flutter开发,我们在客户端内部组织了5次Flutter快速入门的系列分享:Flutter快速入门系列同时也逐步完善内部文档的建设,包括:FlutterSdk源码维护策略、Flutter入门指南、Flutter混合开发方案、Flutter与Native通信方案、Flutter开发环境配置、Flutter组件化工程结构、Flutter开发与调试、Flutter开发工作流、ZFlutter工具使用介绍、Flutter开发之Beetle使用指南等,涵盖了从环境搭建、开发调试到构建发布的整个过程。大范围推广在完成基建二期的建设后,整体基础设施已经能够支撑我们常见的业务,开发工作流也基本顺畅,于是我们开始了在内部大范围推广计划。我们先后改造和新开发了个人主页、我发布的页面、微商详、奇趣数码页等业务,基本涵盖了常见的各种类型的页面和功能,整体开发效率与原生单端开发效率持平,但是在特别复杂的页面的性能表现上,Flutter的表现相对要差一些。部分页面如下图所示:个人主页微页/我发布的/奇趣数码探索前端生态在跨端技术领域我们知道Web技术是天然支持的,如果能把前端生态引入到Flutter中,那么对客户端来说,在业务的支持度上会更上一个台阶,Web的体验得到提升的同时客户端也具备了动态化,基于此背景我们开始探索Flutter在Web上的可能性。技术调研当时可选的开源方案有:Kraken、MXFlutter、FlutterForWeb。KrakenKraken是一款基于W3C标准的高性能渲染引擎。Kraken底层基于Flutter进行渲染,通过其自绘渲染的特性,保证多端一致性。上层基于W3C标准实现,拥有非常庞大的前端开发者生态。Kraken的最上层是一个基于W3C标准而构建的DOMAPI,在下层是所依赖的JS引擎,通过C++构建一个Bridge与Dart通信。然后这个C++Bridge把JS所调用的一些信息,转发到Dart层。Dart层通过接收这些信息,会去调用Flutter所提供的一些渲染能力来进行渲染。Kraken是不依赖FlutterWidget,而是依赖FlutterWidget的底层渲染数据结构——RenderObject。Kraken实现了很多CSS相关的能力和一些自定义的RenderObject,直接将生成的RenderObject挂载在FlutterRenderView上来进行渲染,通过这样的方式能够做到非常高效的渲染性能。MXFlutterMXFlutter是一套使用TypeScript/JavaScript来开发Flutter应用的框架。MXFlutter把Flutter的渲染逻辑中的三棵树(即:WidgetTree、Element、RenderObject)中的第一棵(即:WidgetTree),放到JavaScript中生成。用JavaScript完整实现了Flutter控件层封装,实现了轻量的响应式UI框架,支撑JSWidgetTree的build逻辑,build过程生成的UI描述,通过Flutter层的UI引擎转换成真正的Flutter控件显示出来。FlutterForWebFlutter在Web平台上以浏览器的标准API重新实现了引擎。目前有两种在Web上呈现内容的选项:HTML和WebGL。在HTML模式下,Flutter使用HTML、CSS、Canvas和SVG进行渲染。在WebGL模式下,Flutter使用了一个编译为WebAssembly的Skia版本,名为CanvasKit。HTML模式提供了最佳的代码大小,CanvasKit则提供了浏览器图形堆栈渲染的最快途径,并为原生平台的内容提供了更高的图形保真度。结论我们对以上方案从接入成本、渲染性能、包体积、开发生态、学习成本等多维度进行了对比:接入成本:Kraken≈MXFlutter≈FlutterForWeb渲染性能:Kraken>MXFlutter>FlutterForWeb包体积增量:FlutterForWebFlutterForWeb学习成本:FlutterForWeb
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-25 13:56 , Processed in 0.732878 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表