为什么须要混和计划
具有一定规模的App一般来说有两套成形通用型的此基础库,尤其是穆萨系App,一般须要倚赖很多管理体系内的此基础库。那么使用Flutter重新一气呵成合作开发App的生产成本和风险都较低。所以在Native App展开渐进北迁是Flutter控制技术在原有Native App展开应用领域的平稳型方式。eBay在工作中结晶出两套自己的混和控制技术计划。在此过程中,他们跟Google Flutter项目组展开着紧密的沟通交流,汇报了非官方的许多提议,同时也特别针对他们销售业务具体内容情况展开计划的THF1以及具体内容的同时实现。
非官方提出的混和计划
基本基本概念
Flutter控制技术链主要就由C++同时实现的Flutter Engine和Dart同时实现的Framework组成(其基础建设的校对和构筑辅助工具他们这里不参与探讨)。Flutter Engine负责管理缓存管理工作,Dart VM状况管理工作和Dart标识符读取等工作。而Dart标识符所同时实现的Framework则是销售业务碰触到的主要就API,譬如Widget等基本概念就是在Dart微观Framework内容。
两个民主化里头最数只会调用两个Dart VM。然而两个民主化能有数个Flutter Engine,数个Engine示例共享资源同一Dart VM。
他们上看具体内容同时实现,在iOS下面每调用两个FlutterViewController就会有两个发动机骤然调用,也就意味著会有捷伊缓存(理论上缓存能F83E43Se)去跑Dart标识符。Android类似于的Activity也会有类似于的效用。如果你开启数个发动机示例,注意这时Dart VM仍然是共享资源的,只是不同Engine示例读取的标识符跑在各别分立的Isolate。
非官方提议
发动机广度共享资源
在混和计划方面,他们跟Google探讨了可能的许多计划。Flutter非官方得出的提议从长年上看,他们应该全力支持在同一发动机全力支持Perhaps绘出的能力,最少在逻辑上努力做到FlutterViewController是共享资源同一发动机的资源的。换言之,他们希望所有绘出询问处共享资源同一主Isolate。
但非官方得出的长年提议目前来说没有较好的全力支持。
多发动机商业模式
他们在混和计划中解决的主要就问题是如何去处理交替出现的Flutter和Native页面。Google工程师得出了两个Keep It Simple的计划:对于连续的Flutter页面(Widget)只须要在当前FlutterViewController打开即可,对于间隔的Flutter页面他们调用捷伊发动机。
例如,他们展开下面一组导航操作:
Flutter Page1 -> Flutter Page2 -> Native Page1 -> Flutter Page3他们只须要在Flutter Page1和Flutter Page3创建不同的Flutter示例即可。
这个计划的好处就是简单易懂,逻辑清晰,但是也有潜在的问题。如果两个Native页面两个Flutter
页面一直交替展开的话,Flutter Engine的数量会线性增加,而Flutter Engine本身是两个比较重的对象。
多发动机商业模式的问题
冗余的资源问题.多发动机商业模式下每个发动机之间的Isolate是相互分立的。在逻辑上这并没有什么坏处,但是发动机底层其实是维护了图片缓存等比较消耗内存的对象。想象一下,每个发动机都维护自己一份图片缓存,内存压力将会非常大。插件注册的问题。插件倚赖Messenger去传递消息,而目前Messenger是由FlutterViewController(Activity)去同时实现的。如果你有数个FlutterViewController,插件的注册和通信将会变得混乱难以维护,消息的传递的源头和目标也变得不可控。Flutter Widget和Native的页面差异化问题。Flutter的页面是Widget,Native的页面是VC。逻辑上来说他们希望消除Flutter页面与Naitve页面的差异,否则在展开页面埋点和其它许多统一操作的时候都会遇到额外的复杂度。增加页面之间通信的复杂度。如果所有Dart标识符都运行在同一发动机示例,它们共享资源两个Isolate,能用统一的编程框架展开Widget之间的通信,多发动机示例也让这件事情更加复杂。因此,综合多方面考虑,他们没有采用多发动机混和计划。
现状与思考
前面他们提到多发动机存在许多实际问题,所以eBay目前采用的混和计划是共享资源同一发动机的计划。这个计划基于这样两个事实:任何时候他们最数只能看到两个页面,当然有些特定的场景你能看到数个ViewController,但是这些特殊场景他们这里不探讨。
他们能这样简单去理解这个计划:他们把共享资源的Flutter View当成两个画布,然后用两个Native的容器作为逻辑的页面。每次在打开两个容器的时候他们通过通信机制通知Flutter View绘出成当前的逻辑页面,然后将Flutter View放到当前容器里头。
老计划在Dart侧维护了两个Navigator栈的结构。栈数据结构特点就是每次只能从栈顶去操作页面,每一次在查找逻辑页面的时候如果发现页面不在栈顶那么须要往回Pop。这样中途Pop掉的页面状况就丢失了。这个计划无法全力支持同时存在数个平级逻辑页面的情况,因为你在页面切换的时候必须从栈顶去操作,无法再保持状况的同时展开平级切换。
举个例子:有两个页面A,B,当前B在栈顶。切换到A须要把B从栈顶Pop出去,这时B的状况丢失,如果想切回B,他们只能重新打开B之前页面的状况无法维持住。这也是老计划最大的两个局限。
如在pop的过程当中,可能会把Flutter 非官方的Dialog展开误杀。这也是两个问题。
而且基于栈的操作他们倚赖对Flutter框架的两个属性修改,这让这个计划具有了侵入性的特点。这也是他们须要解决的两个问题。
具体内容细节,大家能参考老计划开源项目地址:
https://github.com/alibaba-flutter/hybrid_stack_manager
新一代混和控制技术计划 FlutterBoost
重构计划
在eBay推进Flutter化过程当中,更加复杂的页面场景逐渐暴露了老计划的局限性和许多问题。所以他们开启了代号FlutterBoost(向C++ Boost致敬)的新混和控制技术计划。这次捷伊混和计划他们的主要就目标有:
可F83E43Se通用型型混和计划全力支持更加复杂的混和商业模式。比如支持主页Tab这种情况无侵入性计划:不再倚赖修改Flutter的计划全力支持通用型页面生命周期统一明确的设计基本概念跟老计划类似于,捷伊计划还是采用共享资源发动机的商业模式同时实现。主要就思路是由Native容器Container通过消息驱动Flutter页面容器Container,从而达到Native Container与Flutter Container的同步目的。他们希望努力做到Flutter渲染的内容是由Naitve容器去驱动的。
简单的理解,他们想努力做到把Flutter容器做成浏览器的感觉。填写两个页面地址,然后由容器去管理工作页面的绘出。在Native侧他们只须要关心如果调用容器,然后设置容器对应的页面标志即可。
主要就基本概念
Native层基本概念
Container:Native容器,平台Controller,Activity,ViewControllerContainer Manager:容器的管理工作者Adaptor:Flutter是适配层Messaging:基于Channel的消息通信Dart层基本概念
Container:Flutter用来容纳Widget的容器,具体内容同时实现为Navigator的派生类-Container Manager:Flutter容器的管理工作,提供show,remove等ApiCoordinator: 协调器,接受Messaging消息,负责管理调用Container Manager的状况管理工作。Messaging:基于Channel的消息通信关于页面的理解
在Native和Flutter表示页面的对象和基本概念是不一致的。在Native,他们对于页面的基本概念一般是ViewController,Activity。而对于Flutter他们对于页面的基本概念是Widget。他们希望可统一页面的基本概念,或者说弱化抽象掉Flutter本身的Widget对应的页面基本概念。换言之,当两个Native的页面容器存在的时候,FlutteBoost保证一定会有两个Widget作为容器的内容。所以他们在理解和展开路由操作的时候都应该以Native的容器为准,Flutter Widget倚赖于Native页面容器的状况。
那么在FlutterBoost的基本概念里说到页面的时候,他们指的是Native容器和它所附属的Widget。所有页面路由操作,打开或者关闭页面,实际上都是对Native页面容器的直接操作。无论路由请求来自何方,最终都会转发给Native去同时实现路由操作。这也是接入FlutterBoost的时候须要同时实现Platform协议的原因。
另一方面,他们无法控制销售业务标识符通过Flutter本身的Navigator去push捷伊Widget。对于销售业务不通过FlutterBoost而直接使用Navigator操作Widget的情况,包括Dialog这种非全屏Widget,他们提议是销售业务自己负责管理管理工作其状况。这种类型Widget不属于FlutterBoost所定义的页面基本概念。
理解这里的页面基本概念,对于理解和使用FlutterBoost至关重要。
与老计划主要就差别
前面他们提到老计划在Dart层维护单个Navigator栈结构用于Widget的切换。而捷伊计划则是在Dart侧引入了Container的基本概念,不再用栈的结构去维护原有的页面,而是通过扁平化key-value映射的形式去维护当前所有的页面,每个页面拥有两个唯一的id。这种结构很自然的全力支持了页面的查找和切换,不再受制于栈顶操作的问题,之前的许多由于pop导致的问题迎刃而解。同时也不再须要倚赖修改Flutter源代码的形式去展开同时实现,除去了同时实现的侵入性。
那这是如何努力做到的呢?
多Navigator的同时实现
Flutter在底层提供了让你自定义Navigator的接口,他们自己同时实现了两个管理工作数个Navigator的对象。当前最数只会有两个可见的Flutter Navigator,这个Navigator所包含的页面也就是他们当前可见容器所对应的页面。
Native容器与Flutter容器(Navigator)是一一对应的,生命周期也是同步的。当两个Native容器被创建的时候,Flutter的两个容器也被创建,它们通过相同的id关联起来。当Native的容器被销毁的时候,Flutter的容器也被销毁。Flutter容器的状况是跟随Native容器,这也就是他们说的Native驱动。由Manager统一管理工作切换当前在屏幕上展示的容器。
他们用两个简单的例子描述两个新页面创建的过程:
创建Native容器(iOS ViewController,Android Activity or Fragment)。Native容器通过消息机制通知Flutter Coordinator捷伊容器被创建。Flutter Container Manager进而得到通知,负责管理创建出对应的Flutter容器,并且在其中装载对应的Widget页面。当Native容器展示到屏幕上时,容器发消息给Flutter Coordinator通知要展示页面的id.Flutter Container Manager找到对应id的Flutter Container并将其设置为前台可见容器。这就是两个新页面创建的主要就逻辑,销毁和进入后台等操作也类似于有Native容器事件去展开驱动。
总结
目前FlutterBoost已经在生产环境支撑着在eBay客户端中所有的基于Flutter合作开发销售业务,为更加负复杂的混和场景提供了全力支持。同时也解决了许多历史遗留问题。
他们在项目开启之初就希望FlutterBoost能够解决Native App混和商业模式接入Flutter这个通用型问题。所以他们把它做成了两个可F83E43Se的Flutter插件,希望吸引更多感兴趣的朋友参与到Flutter社区的建设。他们的计划可能不是最好的,这个计划距离完美还有很大的距离,他们希望通过多分享交流以推动Flutter控制技术社区的发展与建设。他们更希望看到社区能够涌现出更加优秀的组件和计划。
在有限篇幅中,他们分享了eBay在Flutter混和控制技术计划中积累的经验和标识符。欢迎兴趣的同学能够积极与他们一起交流学习。
扩展补充
性能相关
在两个Flutter页面展开切换的时候,因为他们只有两个Flutter View所以须要对上两个页面展开截图保存,如果Flutter页面多截图会占用大量内存。这里他们采用文件内存二级缓存策略,在内存中最数只保存2-3个截图,其余的写入文件按需读取。这样他们能在保证用户体验的同时在内存方面也保持两个较为稳定的水平。
页面渲染性能方面,Flutter的AOT优势展露无遗。在页面快速切换的时候,Flutter能够很灵敏的相应页面的切换,在逻辑上创造出一种Flutter数个页面的感觉。
Release 1.0全力支持
项目开始的时候他们基于eBay目前使用的Flutter版本展开合作开发,而后展开了Release 1.0兼容升级测试目前没有发现问题。
接入
只要是集成了Flutter的项目都能用非官方倚赖的方式非常方便的以插件形式引入FlutterBoost,只须要对工程展开少量标识符接入即可完成接入。
详细接入文档,请参阅GitHub主页非官方项目文档。
现已开源
目前,新一代混和栈已经在eBay全面应用领域。他们非常乐意将结晶的控制技术回馈给社区。欢迎大家一起贡献,一起交流,携手共建Flutter社区。
项目开源地址:
https://github.com/alibaba/flutter_boost作者:eBay控制技术-福居