Flutter混合开发小记

近期主要精力在Flutter混合开发和纯Flutter开发上,话说原生开发现在我只当作“壳”来用了。本篇文章主要介绍我的混合开发经历,从我们项目中遇到的实际问题、到解决方案的确定、到实际运用、到开发遇到的问题以及如何解决、到最终上线、再到优化这几部分讲解。

一、项目中遇到的问题

在实际项目的迭代开发中,业务提出的需求主要是针对项目中固定的三四个模块的修改,尤其是其中的一个模块(我称为S模块),该模块业务极其复杂,涉及到很多业务判断、价格计算、联动控制等。
Android端因为是我主负责的,前前后后将S模块优化了一遍又一遍,从刚开始的所有业务逻辑都杂糅在一起到后来将大模块拆分成各个小模块然后根据业务场景进行组合。
iOS端的S模块由于前期没有规划好,将所有的业务场景都写在一个Controller中,导致该Controller非常庞大,我在前面有篇文章中也介绍过。
综上,每次业务提过来需求,Android端还算在可控范围内,iOS端简直是噩梦,终于体会到什么叫牵一发动全身!

二、解决方案的确定

经过了一个多月的调研、实验最终确定了Flutter混合开发的方案。当然期间也遇到了很多困难,也想过放弃,但最终都一一克服了。这里要提一下官方在1.9.1的版本中介绍的混合开发方案也是实验性的,当时我记得官方在github wiki的开篇就说了该方案的不稳定性,但是后来实际结果证明还是比较稳定的。现在在 这里
官方已经给出了正式的集成方案,大家有兴趣可以参考实验下,我目前还在用1.9.1版本,1.12版本的使用还在规划当中。

三、实际运用

确定好可行性后就开始着手研究如何集成到现有的项目中,好在当时官方wiki也介绍的很清楚,再加上国内也有很多同学们也都早就开始使用了,所以集成的过程整体还算顺利。
UI显示部分,Android采用的是添加
Flutter.createView
的方式,iOS采用的是继承FlutterViewController的方式。通讯部分,均采用的是MethodChannel和MessageChannel。

四、开发遇到的问题以及如何解决

集成过程并非一帆风顺,遇到了很多问题,这里典型的有插件的开发、Android端自定义插件在集成到原生项目后没效果、iOS端setInitialRoute没效果、Flutter端状态如何管理、JSON序列化和反序列化。当然还有其他很多细节部分,这里就不啰嗦了。

首先是插件的开发, 官方文档
介绍的很详细,实际开发中也没遇到太大的阻碍,主要是要针对两端写原生代码,略显繁琐。
插件开发中遇到的最大的问题就是集成到原生项目中没法回调,也就是插件中的onActivityResult不能触发,后来研究源码后发现在添加FlutterView的Activity中重写onActivityResult方法,然后调用
mFlutterView.getPluginRegistry().onActivityResult(requestCode, resultCode, data);
就可以解决。

iOS端setInitialRoute没效果的问题也是在搜索 issues
后找到解决方案,主要思路是在继承FlutterViewController的VC中,在viewDidLoad方法中加入
[GeneratedPluginRegistrant registerWithRegistry:self.engine];

Flutter端状态管理当初面临选择困难症,因为成熟的框架太多,如redux、provider、bloc等,各位可以参考知乎上 这篇文章
的介绍,后来还是选用了 bloc
,其他框架没用过不作评价,bloc框架用起来一个字,“爽”!很容易上手。框架的提供的BlocListener、BlocBuilder,基本能覆盖日常开发中所有的应用场景。虽然还没入选Flutter Favorite,但不影响它广泛的被采用。

最后说说JSON序列化和反序列化,做过原生开发的都知道,json的序列化和反序列化使用gson很方便,而flutter中并没有像gson一样的三方库, 官方
提供的解决思路是使用Flutter自带的dart:convert库,然后配合三方插件json_serializable来完成,虽然没有gson那么智能,但好歹是解决了问题,目前我也在项目中大量的使用,除了稍微繁琐点外无其他副作用。

五、最终上线

因为修改的动作太大,基本将几个常用的模块又用另外一门语言重新写了一遍,为了缩小上线后带来的影响,首先采用的是试点区域上线,经过一个月左右时间的试运行后开始大面积推广使用。从1月中旬上线到现在已经3个多月了,运行情况良好。

六、优化

实际替换过程中,我只针对不连续的两个模块进行了替换,如S模块和D模块,这两个模块都是由原生页面跳转过来,他们之间并无直接的关联,所以我们在测试内存占用的时候发现当进入S和D模块的时候内存会暴涨,但是返回以后内存又会恢复到正常水平,这块没法进行优化的,因为eigne本身就要占用很大的内存。
问题主要出在连续的Flutter页面跳转,我准备将S和D共同的前置模块L也用Flutter来替换掉,替换后发现从L到S内存又经历了一次暴涨,因为加载L和S都分别加载了一次engine,Android端我倒没发现问题,engine应该是共享的,但是iOS端内存立马翻倍了。官方文档关于1.12版本的add to app章节部分有说明,貌似是解决了engine内存共享问题,实验过的同学可以分享下。
我目前采用的方式是集成闲鱼的flutter_boost框架,花了两周的时间进行了替换修改,今天刚刚集成完成,下一篇我会详细介绍集成过程,以及遇到的问题和解决方法。
flutter目前start量已经将react-native远远的甩在身后了,一颗冉冉升起的新星正在改变整个移动开发生态圈。