震坤行移动应用中Flutter技术的实战应用

发表时间: 2024-05-02 22:24


引言


Flutter是Google开源的UI工具包,帮助开发者通过一套代码库高效构建多平台应用,支持移动、Web、桌面和嵌入式平台。Flutter技术已经成为越来越多行业伙伴重点投入的技术建设方向,国内各大厂也都建设了自己的Flutter工程化体系并服务各自的业务场景。Flutter技术带来的收益:

  • 提升开发效率:双端一致,并且热重载可以帮助快速的修改和调试UI
  • 提升交付效率:保证多端可同时发版,业务需求可以同一个截止日期完成
  • 提升用户体验:Flutter提供了双端一致的UI并且有媲美Native的性能
  • 人力节省:节省设计、测试、开发人力成本

从2020年开始,震坤行移动团队面临如下挑战:

  1. 由于公司业务的快速发展,包括开发、产品、测试等在内的人员都会同时负责两个以上的产品,我们希望有解决方案可以提升开发、测试、交付效率
  2. 公司的研发团队分布在北京、上海,虽然全公司采用了规模化敏捷框架SAFe来进行项目管理,但是在移动团队内产品、测试、设计等还是需要和不同端的同学进行沟通交流,我们希望能降低交流沟通成本

经过移动团队的技术调研,我们决定全面拥抱Flutter,提升移动端的研发效能。

App全面转向Flutter的成本和风险较高,目前稳健的做法都是Native渐进式向Flutter迁移,根据业务和技术需求保持Native和Flutter混合并存。本文主要介绍项目中Flutter-Native混合开发相关实践中Flutter和原生之间的交互:页面跳转、数据处理等


混合技术方案选型


FlutterBoost是一个Flutter插件,它的理念是将Flutter像Webview那样来使用,可以轻松地为现有原生 应用程序提供Flutter混合集成方案。FlutterBoost采用共享引擎的实现方式,主要思路是由 Native容器Container 通过消息驱动 Flutter⻚面容器Container,从而达到 Native Container 与 Flutter Container的同步目的。Flutter渲染的内容是由Native容器去渠道的。FlutterBoost帮助处理⻚面的映射和跳转, 开发者只需关心⻚面的名字和参数即可(通常可以是URL)。它具有以下优点:

  • 可复用通用型混合方案
  • 支持更加复杂的混合模式
  • 比如支持主⻚Tab无侵入性方案:不再依赖修改Flutter的方案
  • 支持通用⻚面生命周期
  • 统一明确的设计概念

全局Router构建


在Native和Flutter混合开发项目中,首先我们需要解决的就是利用FlutterBoost构建一个全局Router,统一管理Native和Native、Native和Flutter,Flutter和Flutter之间的⻚面跳转。

在Flutter Module中完成新⻚面的开发,需要在 main.dart中定义相关路由,代码如下:

原生如何打开Flutter页面(Activity或者Fragment形式):通过BoostFlutterActivityFlutterFragment来将Flutter页面打开。

具体实现:定义FlutterRouter类用来打开Flutter Activity和Fragment,其中 flutterRouter map对应main.dart中定义的所有路由,即flutterRouter map包含的路由通过FlutterBoost调用。在后面我们会将openPageByUrl添加原生路由的处理。

在Flutter模块中页面跳转不使用Flutter原生提供的 Navigator实现跳转,而采用FlutterBoost来统一处理。FlutterBoost打开页面的方法为
FlutterBoost.singleton.open
,该方法会调用plugin中的openPage方法,而openPage最终调用到Native层中FlutterBoost初始化所定义的INativeRouter

INativeRouter实现中将路由处理也交给之前定义的FlutterRouter,完善openPageByUrl方法来统一处理所有路由,那么最终FlutterRouter可以用来处理所有Native和Flutter路由。

上述代码中Native路由的处理针对某些路由进行了特殊处理,目的是为了兼容以前的代码。


全局Router参数处理


在路由跳转过程中,我们还需要关注如何传递和接收参数。参数主要包括基本类型、List数据、对象数据,下面分别介绍各种数据类型如何处理。

1. Native -> Flutter

从Native端参数会放入到SerializableMap中,然后传递给Flutter。在Flutter模块我们可以直接获得基本类型等,对象数据通过json传递获得

2. Flutter -> Native

如果是简单的Map参数的话,会直接通过 FlutterRouter 中ARouter处理而不需要特殊处理。如果传递是对象的话会涉及到json转换,在我们项目中是为了保持原来业务代码而使用到对象数据的传递,但是建议后续参数全部采用Map形式传递,可以保证 FlutterRouter处理的统一性。


startActivityForResult处理


在Android中我们经常遇到这种场景:启动另一个Activity并接受返回的结果。那么在跨Module中怎么处理这种情况呢?


1. Native⻚面打开Flutter⻚面并获取返回数据

FlutterBoost通过
FlutterBoost.singleton.closeCurrent(result: result, exts: exts);
方法来关闭页面,该方法会调用FlutterBoostPlugin中的closePage方法。

最终result 不为空就会调用setResult方法返回结果。其中对应result的key是RESULT_KEY = "_flutter_result_";

所以对于startActivityForResult启动的Flutter页面,只需要将返回值放入result map中即可

2. Flutter⻚面打开Native⻚面并获取返回数据

在Flutter中可以直接获取到打开⻚面之后的返回值,这里我们只需要关注返回值map中具体的key-value。

在FlutterBoost中Flutter页面是通过BoostFlutterActivity呈现,追踪源码可以看到最终返回值Map中requestCoderesultCode对应的key为_requestCode___resultCode__


MethodChannel交互


Flutter平台特定的API支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:

  • 应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主 (iOS或Android)
  • 宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言)并 将响应发送回客户端,即应用程序的Flutter部分


在FlutterBoost初始化的时候,可以在BoostLifecycleListener中创建MethodChannel来提供与客户端通信的渠道

在FlutterBoost中创建MethodChannel


总结:


本文主要介绍了Flutter混合开发过程中Native与Flutter之间的交互,包括⻚面调用、参数传递、数据交换。在混合开发过程中,我们实现了全局Router在不同Module可以保持一致性处理,并介绍了⻚面跳转过程中参数的处理和回调、MethodChannel交互。


在实施Flutter混合开发落地之后,主要体验如下:

  • Flutter在UI编写上体验非常好,虽然一开始编写有点不习惯,但是熟练之后开发效率很高
  • 针对复杂列表⻚面,开发体验和性能都有很大提升
  • 减少测试时间,由于双端一致测试同学不用每端都仔细测试,特别是UI方面
  • 原来项目中有一些功能暂时没法迁移到Flutter(如第三方UI库、不支持Flutter的SDK库等),在项目中采用原生Activity嵌套Flutter Fragment的形式来解决,但是这无形中增加了原生与Flutter之间的交互工作
  • 涉及到与原生交互部分需要两端共同商定,并且在修改methodchannel等公用部分,需要留意会不会对其他端有影响


作者简介


李亮,震坤行移动端高级研发工程师, 2019年加入震坤行。

来源-微信公众号:产品技术团队

出处
:https://mp.weixin.qq.com/s/FzJkLufrADkGQQQVG6mhOw