请人做网站要多少,株洲seo优化哪家好,网站建设公司哪家好 地址磐石网络,建设工程公司组织架构图1. 闲鱼Flutter现状
闲鱼是第一个使用Flutter混合开发的大型应用#xff0c;但闲鱼客户端开发最深入体会的痛点就是编译时长影响开发体验。在FlutterNative这种开发模式下#xff0c;Native编译速度慢#xff0c;模块开发无法突破。闲鱼集成了集团众多中间件#xff0c;很…1. 闲鱼Flutter现状
闲鱼是第一个使用Flutter混合开发的大型应用但闲鱼客户端开发最深入体会的痛点就是编译时长影响开发体验。在FlutterNative这种开发模式下Native编译速度慢模块开发无法突破。闲鱼集成了集团众多中间件很多功能无法通过flutter直接调用需使用各种channel到native去调用对应功能。总而言之闲鱼目前Flutter开发面临如下几个痛点
Flutter侧混合编译速度慢Android首次编译10miniOS首次编译20min混合栈编程中历史包袱导致IOS/Android双端返回给Flutter侧的数据可能存在不一致性集成模块开发效率相比模块开发较低单模块页面测试性能数据无法展开
2.解决方案一
2.1方案概述
此项目从立项至今已经很长一段时间由于业务迭代快native插件满天飞情况下想要做到工程模块化拆分难度可想而知如下图是项目立项为模块化拆分业务方需要将各个业务拆分解耦合拆分集团中间件业务封装组件Native业务代码Flutter桥代码Flutter组件库Flutter侧业务代码等多个模块项目初衷就是整理代码提供一个Flutter可运行的干净环境同时需要让flutter可以获取到native几乎所有能力但是编译开发调试时候有想要速度快效率高。能想到的最直接解决方案就是拆包从0-1建立一个最小壳工程然后拆分集团基本中间件封装业务组件Flutter插件等如下是整个项目架构 日常模块化单页面级需要使用最小壳工程其内部又channel的声明和实现通过运行最小壳工程运行得到结果Flutter侧模块开发通过IOC调用到最小壳工程的channel得到返回结果最后将模块化开发以一种pub或者git依赖方式集成到闲鱼FWN主工程即可
2.2 阶段性产出
业务模块化拆分从来都是一种吃力不讨好的活明知道拆出来有收益但是投入产出比不足因此历史包袱代码越来越厚重以至于下一个接收的人都不敢轻易修改代码在模块化拆分时候开始项目时候提出过新起一个干净的工程然后一步步拆分集团中间件期间拆出了Mtop/Login/FlutterBoost/UI Plugin耗时3周/2人得到部分结果就是新业务新界面开发满足基本快速迭代开发缺点也很明显如下所示
拆分梳理Native的中间件繁琐工作量巨大最小化壳工程耗时3周/2人推动业务方拆分基础组件库更难目前项目进展不顺维护成本高拆分壳工程运行结果和主工程可能不一致业务迫切其结果但投入产出比不足比如Flutter单页面性能测试Flutter侧模块化拆分Fass工程一体基石
3.解决方案二
3.1 换位思考
1若自己是业务方需要为Flutter侧去拆分包去构建一个最小化壳工程其成本是巨大的。 2Fass工程一体化依赖一个最小化壳工程的Native运行环境去运行Flutter侧代码可是并非所有的业务方都会提供一个最小化壳工程去运行Fass那么Fass工程一体化/模块开发如果在集团其他运行环境下进展 3最小化壳工程运行环境无法紧跟Native侧的各种版本会导致运行结果不一致情况下也不敢随便使用
如果解决此问题呢个人提出过跨进程实现方式在Android端侧跨进程调用实现方式一直很常见的场景client访问server得结果而Flutter侧和Native侧不就是client和server双端么如下图所示其实Flutter获取数据就是通过MethodChannel/EventChannel获取因此可以换一种方式思考 3.2 IPC跨进程通信Android Binder
期间在Android侧我使用过Android Binder去实现新起一个APP做为壳工程其内部实现了各种插件去访问主工程服务获取结果然后返回给壳工程的Flutter调用但是维护成本依然在同时iOS侧没有对应的实现机制因此此方式被抛弃
3.3 具体方案:Hook代理Socket服务
Android开发应该都熟悉hook和插件化技术其实从之前的Flutter到Native的Chanel架构就可以想到一种思路既然解决不了Native问题那就解决Channel的问题吧Native端侧的IPC方式无法实现换到Flutter侧和Native侧的Channel通信侧去实现IPC吧。参考业务对于插件化hook机制/IPC机制的理解结合自身对于flutter channel的理解可以实现一种利用socket服务去hook method channel和event channel实现方式去代理客户端的method channel和event channel将处理结果通过socket交给服务端去处理拿到服务端真正的method channel和event channel数据即可这才是我心中想要的实现方式就是如此整个架构图如下 客户端是一台手机服务端也是一台手机服务端跑闲鱼FWN主工程客户端跑一个干净的Flutter工程客户端先通过Flutter侧代码去找使用本端有对应的Channel如果有则使用返回结果如果没有则通过Socket请求结果到服务端主工程上主工程根据Socket定义的协议字段去解析然后发起一个channel拿结果之后通过socket将解决返回给客户端客户端拿到了socket结果数据后执行想要的渲染方式即可
或许你有质疑点比如为什么要用2台手机使用一台不可以么 这里我推荐使用2台手机有如下2个原因 1一台手机运行2个APP如果server在后台可能会导致进程资源被回收Socket通信中断 2使用2台手机有一个极大好处是你运行Android的Flutter侧Client代码但是往往你需要验证Native侧双端Server代码数据如果客户端手机/服务端手机是2台只需要改下客户端的IP地址去请求Android手机的Server还是IOS手机的Server就可以验证结果
3.4 尝试验证
比如如下的method channel代码如下
FutureT invokeMethodT(String method, [ dynamic arguments ]) async {assert(method ! null);final ByteData result await binaryMessenger.send(name,codec.encodeMethodCall(MethodCall(method, arguments)),);if (result null) {throw MissingPluginException(No implementation found for method $method on channel $name);}final T typedResult codec.decodeEnvelope(result);return typedResult;}
修复result null的场景如果是我们指定的客户端则通过socket去拿server数据,重点理解Fish MOD:START到Fish MOD:END代码思想就理解了
FutureT invokeMethodT(String method, [dynamic arguments]) async {assert(method ! null);final ByteData result await binaryMessenger.send(name,codec.encodeMethodCall(MethodCall(method, arguments)),);if (result null) {//Fish MOD:START//throw MissingPluginException(// No implementation found for method $method on channel $name);//socket从服务端手机获取值final dynamic serverData await SocketClient.methodDataForClient(clientParams);//Fish MOD:END}final T typedResult codec.decodeEnvelope(result);return typedResult;}
最后通过此中方式验证了MethodChannel/EventChannel数据正常收发的可行性后续还需要在业务场景具体实验耕田
4.结果对比和展望
结果对比 无法方案1和方案2最终都可以解决编译运行时长的问题但方案1在拆分模块和维护模块时候都有很高的成本运行时长虽然降低了但是模块化工作量却加大很多方案2可以完美解决拆分成本和维护成本但是不足之处就是运行环境苛刻可操作性不足其需要2部手机作为运行环境另针对于一些页面跳转逻辑可能客户端手机A触发到服务端手机B上操作性不在同一台手机上当然方案二虽然有一定缺陷却可以解决很多问题因此后续在闲鱼模块化拆分落地项目中在思考是否有更加完美的解决方法。
作者祈晴
原文链接
本文为阿里云原创内容未经允许不得转载