链接:https://juejin.cn/post/6911590460800647175

效果展示

上面铁军中的这个关于我们页面以及转换为了动态化页面。

动态化标签
动态化路由

一个flutter页面转换为动态化页面,只需要添加动态化标签和动态化路由就行了,对业务页面的开发修改很少,相比其他动态化方案是巨大的优势

方案对比

方案名称 美团 满帮 众能
简述 dart文件编译为json,使用自定义运行时调用proxy方法 使用js通过自定义js虚拟机调用flutter业务组件 dart文件编译为lua字节码,使用lua虚拟机调用proxy方法
开发语言 dart js dart
语法支持 不支持async和await 支持async和await
flutter控件支持 全部支持 只能使用自定义组件 全部支持
开发调试 使用dart自带debugger 自定义debugger 使用dart自带debugger
核心原理 使用自定义运行时解析json,调用proxy 通过自定义js虚拟机调用proxy 使用修改后的lua虚拟机调用proxy方法
三个方案都必须使用proxy方法,因为flutter中的dart***了反射,必须通过某种方式通过proxy方法来调用dart方法。 proxy方法如下图,这是扫描铁军App自动生成的:

众能的方案对比美团,优势在于使用了成熟的lua虚拟机的机制,在运行时执行的是指令,例如加***被编译两个loadConstant指令和一个binaryArith指令。而美团的方案核心是自定义的运行时,基本单位是语句和表达式,粒度粗了一个级别,直接的影响就是不支持async和await等异步语法。

众能的方案对比满帮,优势在于自动支持所有的flutter组件、第三方和自定义组件,同时开发调试时是使用flutter自带的编译器和调试器。而满帮方案开发时只能使用js语言,同时只能使用有限的flutter组件,有限的业务组件。

核心原理比喻
众能的方案核心其实和乐高积木一样:
普通flutter页面就像上面这个塑料恐龙,要改动一点必须在工厂重新生产。

使用众能动态化的页面,相当于使用很多个小块的乐高积木模仿出了原始的页面,小块的乐高积木就是proxy方法。 所以动态化页面其实是高仿的页面,和原始的页面有些细微的不一致。 但是优势就是动态化的页面可以在自己在运行时修改。

动态化流程1-jenkins打包

jenkins流水线在xcode编译前加入了动态化工具下载,以及动态化编译就是流程图中黄色的部分。

动态化流程2-启动注册路由

每一个动态化dart文件都会编译出.out字节码文件,但只有带routerModel的页面.out文件都才要在启动时执行生成routerModel

.out字节码文件就是上图这样,在启动时执行这个字节码就会生成routerModel,然后动态化虚拟机就休眠了,直到进入动态化页面才会启动。

这个字节码的内容是和lua字节码完全一致的,甚至在项目初期真正的lua字节码可以在mars_vm中运行并输出一样的结果,python、java等虚拟机中字节码也是类似结构,都有指令集,本地变量集合等信息。 虚拟机是另外一种语言来执行目标语言的,例如lua官方虚拟机是使用c语言来执行lua,也有go语言版本的。python虚拟机有java、c、go等多个版本。 众能的这个虚拟机是dart实现的,可以执行lua和dart。

动态化流程3-进入页面

进入页面后就会执行路由routerModel的block,完成页面初始化为为statefullWidget,并按照StatefullWidget本身的生命周期调用对应方法。

最简单的虚拟机指令展示

动态化运行hello_world代码,完成hello world字符串打印,这个在虚拟机里面是比较复杂的,因为要用到包加载等功能。 最简单的指令是算数运算指令,例如下面这个加法。

a = b + 100

会被编译为三条指令,load指令从寄存器中加载b到栈顶,load指令从常量表中加载c到栈顶, 执行算数指令把栈顶的两个数弹出进行算数运算,结果放入a寄存器的位置。

待完善的功能点

1、目前虚拟机调试时不能和原始的dart代码对应上,还好预留了行号信息等字段,一个月内应该可以加上。

2、目前的命名空间实现不够完善,同一个库内类名不能重复。 3、调用proxy方法的指令过多,通过修改命名空间的机制,应该可以把指令数减半。 4、没有实现方法缓存,反复调用同一个方法的话,会重复使用指令加载这个方法。

文章到这里就结束了,你也可以私信我及时获取最新资料。如果你有什么意见和建议欢迎给我留言。