50

Flutter在京东7FRESH的业务实践

 4 years ago
source link: https://www.tuicool.com/articles/IRbMRjz
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

2018年12月Flutter 1.0正式版本发布,与此同时,7FRESH也选择在活动页、7Club、接龙及返佣等垂直业务中使用Flutter开发并灰度上线。具体页面如下:

uIRb6zJ.jpg!web

如上所示,上边是使用Flutter开发的活动页,下边是使用H5开发的活动页,可以很直观地感受到用Flutter开发的页面,在打开页面时白屏时间更短,体验更好,这也是我们选择Flutter的原因。

基本架构

在实际开发的过程中,并形成了适合我们的基本架构,如下图所示:

mIB7zq2.png!web

分别为 业务层和通用组件层; 通用组件层包含了业务组件、UI组件、基础组件;

  • 业务层 就是基于通用组件层开发的具体业务,比如接龙、活动页、返佣、晒单等具体业务;

  • 业务组件 中包括了分享、统计埋点、通用商品组等通用的组件,可以为各个业务模块,提供快速复用的能力;

  • UI组件 中主要是包括通用的Widget,如Button、CoutDown、Swiper等;

  • 基础组件 为上层提供统一的基础能力,如混合页面栈管理、路由管理、图片缓存、热更新等。

我们遇到的问题

7FRESH App 也是基于原有的基础库和业务组件这样的前提下,去做Flutter实践;在这个过程中也踩过很多坑;比如:状态管理怎么做?怎样混合开发及工程管理?页面栈管理?图片缓存问题?Native通信及如何复用已有功能?性能分析?

状态管理方案

我们先比较一下状态管理的方案:

ueuq2yA.jpg!web

综合原因,我们目前采用Provider作为状态管理的方案,一方面Provider解决了刷新范围问题,使用相对简单,提高了性能,职责相对清晰;另一方面也是Google推荐的状态管理方案;Provider使用如下:

1、首先在pubspec.yaml中增加provider依赖

Zviuuq3.png!web

2、定义Model,这里使用mixin,混入了ChangeNotifier,调用notifyListeners()通知刷新 

BjYBJjf.png!web

3、我们需要页面中build方法中注册共享的Model;由于多状态管理,所以使用到了MultiProvider和具备通知刷新功能的ChangeNotifierProvider

Nr6BJfn.png!web

4、比如,购物车数量展示,这是一个局部刷新的需求,首先上图中我们已经注册CartNumModel,然后我们通过消费者Consumer获取新的状态,实现局部刷新。如下:

QruUvaI.png!web

问题来了,Provider是如何实现刷新颗粒度的控制?如下:

1、Provider通过InheritedProvider(继承了InheritedWidget)实现了状态的共享,如下

j2IbumM.png!web

2、然后,ChangeNotifierProvider继承的ListenalbeProvider,其实是一个StatefulWidget,具备了状态变化的能力;

3、Model继承的ChangeNotifier,而ChangeNotifier是一个发布者-订阅者模式,所以具备了通知刷新的能力;

4、ChangeNotifierProvider在初始化时,通过混入的代理对象_ListenableDelegateMixin<T extends Listenable> 把setState注册到Model,核心代码如下:

IV7Rzmy.jpg!web

5、而Model在通过notifyListeners()通知刷新时,就是调用上图listener的Function,调用listener即调用setState,如下,从而达到局部刷新的过程.

jUjuAjy.png!web

混合开发及工程管理

对于代码管理,Android、iOS、Flutter对应三个git仓库,分别管理;

工程管理及工程模式上,通常有两种方式;

一种是源码依赖。优点就是集成便捷,方便调试,修改flutter代码,实时运行代码即可生效,便于调试;缺点就是团队其他开发人员必须都需要安装flutter编译环境。首先我们将flutter工程和Native工程放在同一目录下;

对于Android,在原生项目中做如下修改,首先在settings.gradle中增加配置:

fUBBjqM.png!web

然后在app的build.gradle中增加flutter依赖即可,如下:

bQbuqmI.png!web

对于iOS,也可参考官方步骤,为了方便开发,我们修改了点内容,官方脚本中在打包的时候是flutter.framework支持模拟器,所以在提交appstore的时候是提交不成功的,所以我们修改了一下脚本,在release模式下,从framework中移除了对模拟器的支持。如下,在Podfile中增加如下配置:

uUvIFfE.png!web

在"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh"文件中修改以下配置,为了不影响sdk环境,可以复制此脚本作为副本,xcode的build phases菜单中单独引用.

V3IJr2I.png!webJnEfEzA.png!web

另一种是构建产物依赖。优点就是不影响原生项目,其他开发人员不需要任何配置和安装环境,基本无感知的,缺点就是调试和定位问题比较麻烦。对于Android,Flutter构建生成aar,通过gradle依赖接入即可,对于iOS,Flutter端构建生成framework,通过以pod方式依赖接入即可;构建产物依赖也为后续通过maven管理及组件化创建了条件。

目前,我们在debug模式下使用的源码依赖,在release下使用了构建产物依赖,编译时通过是否debug进行区分,大概如下:

3QNRZzi.png!web

混合页面栈管理

我们采用了Flutter引擎共享的方式去解决内存问题,同时借鉴WebView管理页面栈的方式管理Flutter栈,采用全局路由协议进行页面间的通信和跳转.

全局路由管理

协议定义如图,每一个部分都是变量.

MVNFvq6.jpg!web

基于MethodChannel传递数据,通过路由协议实现跨技术栈访问Native\H5\Flutter\RN,不用关心此功能是用什么技术栈实现;同时,解耦模块间的跳转或功能的调用;也解决了Native功能复用的问题;

网络模块

目前是通过路由协议复用Native网络的能力:一方面Native侧对网络做了一系列优化,如HTTPDNS、HTTPS的验证等等;一方面基于资源的投入,短时间内很难做到Native的优化;Flutter本身的网络库,如dio也是不错的选择。埋点和分享目前也是通过路由协议复用Native端的能力;通过路由协议的好处是不用关心具体实现.

图片缓存方案

我们研究了fade_in_image、cache_network_image缓存库,fade_in_image仅支持内存缓存;cache_network_image文件缓存策略无法满足我们的要求,最终,我们选择了基于fade_in_image作为基础,进行了扩展,优化内存缓存、增加二级缓存,同时使用LRU作为缓存管理策略.

性能分析对比

对于Flutter和H5运行性能对比我们分别在debug和release模式上进行了性能测试,当然release模式的性能是要高于debug模式的,因此以下我们就debug模式的检测数据对Flutter与H5进行性能对比分析。这里我们用Android Profiler进行性能指标检测,下图分别是接龙列表Flutter与H5页面的性能检测数据:

ERjQZfE.png!web

INB3ia7.png!web

首先,我们看 CPU,在启动的时候,Flutter对CPU的占用峰值在24.9%,然后页面加载完后降到了10%左右,之后也没有太大的波动,而H5对CPU的占用峰值达到了33%,之后也一直居高不下,偶尔有降低也很快回升,如图分析,H5相对于Flutter在绘制以及与Native交互通信方面对CPU的消耗高出很多。

内存上两者的峰值都超过了300M,但可以看出Flutter对内存的消耗是要稍高于H5的,页面数据加载完成之后趋于稳定,Flutter的稳定在302.3M,H5的稳定在257.2M。

最后再来看下帧率(FPS),这个是跟用户体验直接相关的,如果帧率过低导致丢帧页面卡顿的话,会直接影响App用户的留存率的,对于帧率,Flutter这边是用Flutter插件自带的Inspector工具来检测帧率变化的,H5则是打开了手机的GPU呈现模式分析,直接以条形图来展示帧率的变化。如下图:

auYv6jQ.png!web

从上图可以看出Flutter的渲染指数是很高的,它自带有渲染引擎,这使得Flutter页面渲染滑动时更平滑顺畅,交互更加友好。

通过以上分析我们可以得出结论,Flutter除了在内存消耗方面要稍高于H5外(项目中Flutter使用了引擎复用,所以在首次打开时内消耗较大,再次打开内存消耗小很多),在CPU资源占用、渲染方面性能都要高于H5.

关于人效

经过这段时间的实践经验,在开发人效方面,同一个需求,使用Native和Flutter开发大概可以得出下面的数据:

rAFVRbN.png!web

如图所示,目前Android和iOS两端,使用Native开发,原来需要6人天的需求,使用Flutter只需求4人天,至少为我们节省了30%的人力;而节省的人力可以投入到其它的需求研发.  

未来期望与规划

Flutter 1.9.1版本已于9月中旬的GDD大会发布,其中支持web平台的Flutter已经合到主干,意味着更好地支持三端又近了一步,我们也会持续关注;同时,7FRESH也会和京东中台ARES跨端团队保持紧密的联系,在组件化、动态更新、工具支持化等方面持续发力,一起为京东内部及行业内的Flutter生态做出一点贡献.

下图为我们的技术交流群二维码,欢迎各位技术爱好者加入交流.

N73MJb3.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK