基于JS的高性能Flutter动态化框架MXFlutter

导语:18年10月份,手机QQ看点团队尝试使用 Flutter,做为iOS开发,一接触到Flutter就马上感受到,Flutter 虽然强大,但不能像RN一样动态化是阻碍我们使用她的唯一障碍了。看Google团队对动态化的计划,短期内应该不会上线,所以自己动手,启动了这个技术探索项目。

基于JS的高性能Flutter动态化框架

可能是目前放出来的相对最完整的Flutter动态化方案

简介

项目代号:MXFlutter (Matrix Flutter)

核心思路是把 Flutter 的渲染逻辑中的三棵树中的第一棵,放到 JavaScript 中生成。用 JavaScript 完整实现了 Flutter 控件层封装,可以使用 JavaScript,用极其类似 Dart 的开发方式,开发Flutter应用,利用JavaScript版的轻量级Flutter Runtime,生成UI描述,传递给Dart层的UI引擎,UI引擎把UI描述生产真正的 Flutter 控件。所以在iOS上是完全动态化的 ,完整代码在github,如果能帮助到大家,请给MXFlutter点个Star,给我们动力继续更新下去^_*,github TGIF-iMatrix MXFlutter

继续前先瞥一眼整体的架构,一句话介绍MXFlutter,就是用JavaScript,以Flutter的写法开发Flutter。汗…还是有点绕,大家看下面贴出来的代码吧。

效果

以下截图是在MXFlutter框架下用JS开发,大家可以把上面的源码下载下来,里面有完整的JS代码示例:

这个是APP示例截图

下面是UI截图对应的JS代码,没错,你没有眼花,这个是真的 JavaScript 代码,可以在 MXFlutter 的运行时库上渲染出 Flutter 的UI

源码中还有更丰满的示例,高仿知乎页面JSFlutter版
https://github.com/TGIF-iMatrix/MXFlutter/blob/master/js_flutter_src/app_test/zhihu/home/home_page.js。

这是对应UI,已经接近在线上版直接使用了。

这个漂亮的知乎页面,是用Dart版转JS而来,在此鸣谢作者许吉友 ,大家可以关注一下他。

现状

MXFlutter虽然各个模块已相对完整,但投入生产还需要解决其中的BUG,由于19年初,小组启动新项目,非常繁忙,几乎没有时间继续开发,从3月份一直暂停,目前人力仍然很紧张,如果大家有兴趣,期待小伙伴们一起加入,共同丰富 MXFlutter 动态化能力。

0x00 分享下动态化探索过程中的几个炮灰方案

Flutter 动态化方案一:静态解析Dart语言,生成UI描述

Dart 本身是描述语言,IDE 的 Outline 工具可以解析 Dart 代码生成树形结构,我们可以利用其源码,生成 JSON UI 描述,相关代码:https://github.com/flutter/flutter-intellij/blob/b6461e8d8ed3857a9e4350bc61133c8f48249f43/src/io/flutter/preview/PreviewView.java

dart-sdk: analysis_server

静态解析 Dart 缺点,不能写逻辑,对编写UI代码有很多限制,不能写判断语句,不能写函数,要支持这些成本很高。所以只好放弃。

快速介绍下Flutter的核心渲染模块三棵树

响应式UI框架

  1. WidgetTree:Widget 里面存储了一个视图的配置信息,可以高效的创建(build)和销毁
  2. Element 是分离 WidgetTree 和真正的渲染对象的中间层, WidgetTree 用来描述对应的Element 属性
  3. RenderObject 来执行 Diff, Hit Test 布局、绘制

第一棵树有完整的UI描述信息,那么我只要JIT下通过 DartVM 创建第一棵树,其他耗时的操作都丢到AOT里去。

Flutter 动态化方案二:动态运行 Dart 语言,生产UI描述

和方案一静态解析Dart对比,第二个方案是写一个极其轻量的运行时库,让编写UI的Dart 代码运行了起来,生成树形结构,再序列化为 JSON(debug),FlatBuffers (release)UI 描述。可以称之为动态解析方案

具体渲染逻辑

总体架构

架构也有了,方案也有了,要Run起来还有几个麻烦事要忙活,DartVM 要抽出来,Dart JIT层的轻量级运行时库,Dart AOT层把DSL转成真正Widget的UIEngine也要写哦,就是图中黄色和红色的三部分

抽离DartVM

无法简单修改编译条件抽离

Dart源代码在进行编译时会通过DART_PRECOMPILED_RUNTIME宏进行条件编译从而在Debug版编译JIT模式,Release版编译AOT模式。并且这两种模式是互斥的,无法同时存在。

简单的解决方法是

我们单独编译出一个DartVM,打包成动态库,修改导出符号,避免符合冲突

引入DartVM还需要的工作

  • 开发DartVM与Native互通接口,参考了Flutter,使用Native Extension和Dart_Invoke实现互相调用
  • 双DartVM调试方案,两个DartVM独立运行,通过远程端口单独调试DartFlutter
  • 支持引入第三方库,DartFlutter在打包发布时会通过shell脚本分析.packages文件将依赖库自动打包随Dart File Zip一起随包下发。
    常用库可以预先打包的App本地,减少下发文件大小

一个暂时无法解决的问题

安装包过大,DartVM增大安装包30M,如果加上原本的AOT40M,整个Flutter安装包会增大到70M,用DartVM不现实。怎么办呢。

0x01 最终方案JavasSriptCore 替换DartVM

可性能分析

  1. JavasSriptCore 是iOS官方库,不增加安装包
  2. Dart代码和JS代码非常相近,可以用工具转换
  3. JavasSriptCore 与 Native有更方便的互调接口
  4. ReactNative 已验证通过JS开发App能力是可行的
  5. JS的执行效率是DartVM的3倍编码1M的JSON只需 2毫秒

需要解决的问题

用JS开发假的Flutter Runtime
封装JavasSriptCore与Native、 Flutter互调接口

0x02 讲解下MXFlutter的渲染原理

渲染树

两个重要的数据结构

  • MXScriptWidget
  • MXWidgetTree

MXScriptWidget管理一个Script页面或控件,负责创建管理 ScriptWidgetTree,以自增ID与Flutter对应Widget相互调用,每次Build都会创建一个新的MXWidgetTree

MXFlutter 事件

在 JS 侧 buildWidget 时,我们会对 function 事件,生成自增的唯一 callbackID,并与 widgetID 组合拼接成 widgetID/callbackID,作为事件的唯一标识。用户点击界面某个 button 时,事件由 Flutter 侧传到 JS 侧,通过解析 widgetID/callbackID,找到对应 widget 的 callback,完成事件处理。

MXFlutter 高效的动态列表

通过在 JS 侧,ListView 调用 Build 方法时,提前展开 child, 并为 ListView 增加 children 成员变量。此时,因为仅有数据配置,不会有多余的 Layout 过程,所以速度是非常快的。

在 Flutter 侧,ListView 仍然是动态创建,滑动列表,MXFlutter Engine 根据 Children 数组里的配置数据,创建真正的 Flutter WidgetCell,效率与原生相同完全一致。

MXFlutter 动画的方案

动画参数在VM层配置一次,动画开始后在Flutter层闭环循环rebuild,形成动画效果,这个是比较通用的做法了。

0x03 渲染优化

不管JSWidget创建有多快,总是有跨语言执行,所以减少Build次数和减小Build出来的DSL UI描述大小,可以优化性能。

渲染优化1-局部刷新:配置树Diff

一个事实

自动对比两次Widget 无论如何都没有直接创建一个新的快,如果开发者不参与,由框架来自动计算Diff是得不偿失的

可行的方法

牺牲响应式UI框架的设计模式
采用和Native、Web的方式,由开发者参与自己设置Diff的节点,即根据ID获取对应Widget,修改Widget参数,Rebuild生成新DSL

渲染优化2-局部刷新-嵌套节点

  • MXScriptWidget 是一个具备Build WidgetTree,缓存Callback映射表,动画支持的基本单位。可以作为普通FlutterWidget来使用。
  • 在Flutter层,如果Widget树中节点有MXScriptWidget,则在对应节点上创建MXFlutterWidget自定义控件
  • 两个子树可以相互对应获得局部刷新,callback回调,动画支持,Rebuild时所生产的UI DSL 大大减少,加快刷新速率

渲染优化3-可以分离动态和静态控件

MXStatelessWidget 可以通过使用无状态的ScriptWidget来向框架标示,其下面的子树,在每次build中不会变化,其build结果会被缓存,下次在Flutter层直接复用

内存-跨层镜像对象的生命周期

VM层,Flutter层,Native层镜像对象的生命周期如何控制?
参考苹果 iOS JavaScriptCore 和 Objective-C的解决方法

  1. 以Flutter层的对象生命周期为主
  2. 在VM层增加WeakMap支持,不增加对象引用计数,Flutter层释放之后,释放VM层对象
  3. 在Native层使用 JSManagerValue,VM层对象释放后,Native的引用被自动置空

线程问题

参照业界RN等框架的设计,VM层跑在一个单独的后台线程

  1. 从Flutter层通过Native通道调用到VM,发生两次线程切换
  2. Flutter UI层和MXScript层是异步调用,限制动态控件的架构设计

一个可行方案
修改FlutterEngine ,定制开发Dart->Native->VM 这个通道,调用到VM不切换线程

VM不新建线程,直接由Flutter UI Thread 消息循环驱动,这样也同时支持了和Flutter UI 层的高效同步调用,但要注意从Native调用到VM,需要通过定制FlutterEngine的接口。

0x04 让开发者写出优雅的代码

让开发者写出优雅的代码,咳咳,这里有点吹了,总之,我们想让使用MXFlutter的开发同学写出来的代码看来正规一些,好看一些。

  • 完美支持Dart Flutter语法
  • 定义所有Flutter 中同名Widget类,构建Widget的参数类,支持相同的Build方式,SetState触发刷新,事件响应函数
  • Callback函数自动生成CallbackID
  • Callback函数自动This绑定
  • ListView 像Dart层一样开发,支持itemBuilder回调函数

参考JS示例源码
TGIF-iMatrix home_page.js

0x05 MXFlutter 基础建设

因为 JavaScript 不支持模块化开发,不能引用其他文件代码,我们参照 RN,使用 Node.js 的模块化代码,在Native 层支持 require 语法。开发时,IDE最好选用 VSCode,因为可以按装JS插件,直接运行调试JS

另外,我们通过重定向模拟器 JS 路径文件到开发机,用户修改完 JS 文件,便可直接看到相应修改,实现模拟器的页面热更新。

结语

由于时间紧张,MXFlutter还有很多遗留的问题,作为一个技术探索,非常辛苦但非常有趣,期待各位大牛指导,期待小伙伴们提出问题一起讨论解决。

要了解全部,一定要拉下源码,运行起来看看,有问题可以留言一讨论,MXFlutter会持续更新。

其他项目成员有luca浪哥,nice,yockie帅哥贡献了动画,控件,示例APP等核心实现, chaodong老师负责了DartVM方案,IP老师帮忙提供了单元测试,健身大神yofer老师负责了代码维护,工具建设。

Image placeholder
akin520
未设置
  59人点赞

没有讨论,发表一下自己的看法吧

推荐文章
探秘K1 Power:如何打造一台坚若磐石的高性能小型机?

熟悉服务器领域的朋友,必然对浪潮K1小型机或多或少有所了解。在当年关键业务主机市场寡头垄断的格局下,浪潮400多位工程师耗费4年时间,于2010年成功研制出了K1小型机,为市场注入一股新的血液。使得中

基于jquery开发的UI框架有哪些?

基于jquery开发的UI框架有哪些?1、国产jQueryUI框架(jUI)DWZDWZ富客户端框架(jQueryRIAframework),是中国人自己开发的基于jQuery实现的AjaxRIA开源

Kafka 优秀的架构设计!它的高性能是如何保证的?

应大部分的小伙伴的要求,今天这篇咱们用大白话带你认识Kafka。Kafka 基础消息系统的作用大部分小伙伴应该都清楚,这里用机油装箱举个例子:所以消息系统就是如上图我们所说的仓库,能在中间过程作为缓存

基于JWT规范实现的认证微服务

本文由公众号EAWorld翻译发表,转载需注明出处。作者:MarceloFonseca译者:白小白 原题:Buildinganauthenticationmicro-servicewithJWTsta

Flutter路由项目实战之fluro

github:https://github.com/zhengzhuan...关于flutter路由,在小项目中,就按照原生写法,但是在大型项目中,这样的我就不会进行推荐,我这里使用的fluro路由管

一小时快速搭建基于阿里云容器服务-Kubernetes的Web应用

本文面向的读者如果您是一个Kubernetes的初学者,本文可以帮助你快速在云上搭建一个可实际使用的集群环境,并发布自己的第一个应用。你无须提前准备任何的硬件资源或者下载任何的软件包。 如果您已经有一

PHP 高性能 Excel 扩展 1.2.7 发布

为什么使用php-ext-excel-export xlswriter是一个PHPC扩展,可用于在Excel2007+XLSX文件中写入多个工作表的文本,数字,公式和超链接。 它支持以下功能: 100

为高性能优化 PHP-FPM

PHP是无处不在的,可以说是互联网Web应用上使用最广泛的语言。 然而,它的高性能并不为人所知,尤其是在涉及到高并发系统时。这就是为什么对于这样特殊的用例,正在被Node(是的,我知道,它不是一种语

DPVS – 小米高性能负载均衡器

随着互联网的快速发展,负载均衡也承担着越来越重要的角色,对于小米这种快速发展中的年轻公司来说,负载均衡的稳定及高性能更是重中之重。本文将主要介绍小米基于DPDK的高性能负载均衡软件DPVS(DataP

NVIDIA再放“大招”,拓宽高性能计算边界

11月19日,在丹佛2019全球超级计算大会(SC19)上,NVIDIA创始人兼首席执行官黄仁勋进行了主题演讲,并宣布了NVIDIA在高性能计算领域的最新动态与成果。这些成果表明,NVIDIA正在将自

京东云和英特尔“花样”升级高性能云硬盘

数据,已成为这个时代的基调。当我们因为数据带来新的机遇而喜不自胜的时候,也常常会不可避免地遇到一些随之而来的困扰。与如何更好地使用数据相比,数据的存储和管理是更棘手的问题所在。面对海量数据爆炸式的增长

干货 | 揭秘京东数科强一致、高性能的分布式事务中间件JDTX

导读:在分布式数据库、云原生数据库、NewSQL等名词在数据库领域层出不穷的当今,变革——在这个相对稳定的领域已愈加不可避免。相比于完全革新,渐进式增强的方案在拥有厚重沉淀的行业则更受青睐。同所有分布

揭秘!一个高准确率的Flutter埋点框架如何设计

背景用户行为埋点是用来记录用户在操作时的一系列行为,也是业务做判断的核心数据依据,如果缺失或者不准确将会给业务带来不可恢复的损失。闲鱼将业务代码从Native迁移到Flutter上过程中,发现原先Na

基于Pandas+ECharts的金融大数据可视化实现方案

前言最近无意中看到一篇文章,介绍的是在IPythonNotebook里实现ECharts的可视化效果。我个人对ECharts一直是推崇有加,是baidu发布的开源项目中我比较喜欢的一个,绝对是良心之作

jquery和js的区别是什么?

jquery和js的区别是什么?一、首先来看一下jQuery和js的概念jquery是一个快速、简洁的JavaScript库,极大的简化了javascript编程。js是一种脚本语言,常用于网页客户端

js中的高阶函数

高阶函数高阶函数是函数式编程的一种代码实现方案,一般把接受一个或多个函数作为参数,或者返回一个函数的函数叫做高阶函数。js中最常见的一些高阶函数如闭包(返回函数),一些内置函数(传入函数)等。Arra

jsp和css的区别是什么?

jsp是什么?JSP全名为JavaServerPages,中文名叫java服务器页面,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码;标签通常以结束。JSP技术有点类似ASP

jsp和css的区别?

一、JSPJSP全名为JavaServerPages,他实现了Html语法中的java扩张(以形式)。JSP与Servlet一样,是在服务器端执行的。通常返回给客户端的就是一个HTML文本,因此客户端

vuetifyjs的优点是什么?

官方网站:https://vuetifyjs.com/zh-Hans/Vuetify优点:几乎不需要任何CSS代码,而element-ui许多布局样式需要我们来编写Vuetify从底层构建起来的语义化

react-native中IOS的webview和js层通信 - UIWebview

前言在9012的最后一篇写到了在rn中安卓的webview的通信原理,而作为0202年的第一篇,继续讨论上年rn中webview通信剩下的部分。背景:对于webview,了解过的人都知道在ios端会存

基于Redis实现Spring Cloud Gateway的动态管理

引言:SpringCloudGateway是当前使用非常广泛的一种API网关。它本身能力并不能完全满足企业对网关的期望,人们希望它可以提供更多的服务治理能力。但SpringCloudGateway并不

为什么说谷歌Anthos是kubernetes的翻版?

在本周纽约的一次会议活动中,谷歌谈到了Anthos。那么,Anthos到底是什么?有哪些新功能?本文将逐一解答!什么是Anthos?从官方资料来看,Anthos是谷歌的混合云平台,主要作用是保护客户的

为什么说Kubernetes的崛起预示着云原生时代到来?

现在,云原生、Kubernetes已经成为企业IT领域的时髦概念,几乎所有的企业都在关注;如果不提这些概念,好像企业就会在云市场竞争中失去绝对话语权。那么,云原生和Kubernetes是怎样一种关系?

聊聊chronos的DeleteBgWorker

序本文主要研究一下chronos的DeleteBgWorkerDeleteBgWorkerDDMQ/carrera-chronos/src/main/java/com/xiaojukeji/chron

跨平台开发的救星-让我们来了解一下flutter

第一次看文章的朋友可以关注我,会不定期发布Android面试内容、进阶专题等等。简介很多人已经用上了flutter,今天就来介绍一下Flutter架构Flutter框架分三层 Framework,En