【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

京东:将 Flutter 扩展到微信小程序端的探索

  • 2019-09-27
  • 本文字数:3341 字

    阅读完需:约 11 分钟

京东:将Flutter扩展到微信小程序端的探索

ARES 作为京东技术中台的多端融合技术团队,聚焦于跨端开发技术框架和平台搭建,包括但不限于 RN、Flutter、小程序等技术栈。目前已经广泛应用于京东商城、京东金融、京东到家、京东拼购等京东 La 系核心 APP 内,帮助业务团队低成本、快速开发自己的业务,以应对市场的瞬息万变之势。


Google Flutter 是一个非常优秀的跨端框架,不仅可以运行在 Android、 iOS 平台,而且可以支持 Web 和桌面应用。在国内小程序是非常重要的技术平台,我们也一直思考能否把 Flutter 扩展到小程序端?我们团队之前已经开源了 Alita 项目,Alita 可以把 React Native 的代码转换并运行在微信小程序平台。受此启发,我们认为同样是声明式 UI 框架的 Flutter 同样可以运行在小程序平台。


所以,我们发起了flutter_mp开源项目。以微信小程序为例,不过现阶段,flutter_mp 项目还处于早期的实验阶段,很多功能还在探索规划中,欢迎大家在 Github 上随时关注我们的最新进展,或者参与项目共同探索。

原理简介

虽然还有诸多功能未完成,我们先来谈谈整个 flutter_mp 的实现原理。篇幅原因,下面我们将只对 flutter_mp 几个重要的部分进行简单说明。


先看下 flutter_mp 的实际效果:



Flutter 版官方 layout 样例



通过 flutter_mp 转换并运行在小程序端效果

声明式 UI 的处理

Flutter 是声明式 UI 框架,声明式 UI 只需要向框架描述 UI 长什么样子而不用关心框架具体的实现细节,具体到 Flutter,上层的 UI 描述使用底层的 skia 图形引擎处理就是原生 Flutter,而把底层处理换成 html/css/canvas 就是 flutter_webflutter_mp 则是探索在类小程序上对这些 UI 描述的处理。


我们看一个最简单例子


var x = 'Hello World'
Center( child: Text(x));
复制代码


对于上面的 UI 结构,我们只需要在小程序的 wxml 文件里,用如下的结构对应就 OK 了。


// wxml部分<Center>   <Text>{{x}}</Text></Center>
// js 部分Component({ data: { x: 'Hello World' }})
复制代码


虽然实际的结构要比上面的情况复杂的多,不过通过上面简单的例子,我们知道起码要做两个事情:


  1. 我们需要根据 Flutter 代码生成相关小程序 wxml 模版文件

  2. 收集 wxml 渲染需要的数据,放置到小程序组件的 data 字段。

wxml 结构生成

我们知道小程序是无法动态操作节点的,wxml 结构需要预先生成,所以 Flutter 运行在小程序之前,会存在一个编译打包阶段,这个阶段会遍历 Dart 代码,根据一定规则生成 wxml 文件(编译阶段还会做下文将要提到的另外一个重要事情 — 把 Dart 编译为 js)。


具体的,我们首先会将 Dart 源码处理为可分析的 AST 结构,AST 是源代码的树型表示结构。然后我们深度遍历这份 AST 语法树结构,生成目标 wxml,整个过程如下:



构建 wxml 结构的难点在于: Flutter 不仅是声明式 UI 还是“值 UI”,什么叫“值 UI”?简单来说,Flutter 把 UI 看成是一个普通的值,类似于字符串,数字一样的值,既然是一个普通的值,就可以参与所有的控制流程,可以是函数的返回值也可以是函数参数等等。而小程序的 wxml 虽然也是声明式 UI,却不是“值 UI”,wxml 更加像模版,更加的静态。怎么用静态的 wxml 表达动态的“值 UI”是构建 wxml 结构的关键所在。


看个例子:


Widget getX() {    if (condition1) {        return Text('Hello');    } else if (condition2) {        return Container(            child: ...        );    } else if (condition3) {        return Center(            child: ...        );    }    ...}
Widget x = getX();
Center( child: x // < --- 如何处理这里的 x??);
复制代码


这里的 child: x ,x 是一个动态值,它的具体值需要在运行阶段才能确定,它可能是任意的 Widget,如何在静态的 wxml 上处理这里动态的 x?受 Alita 框架的启发,这里主要是借助于小程序 template 的动态性(template 的 is 属性可以接受变量值)。有如下几步:


  1. 首先在遍历 Dart 源码 AST 结构的时候,会把每一个独立完整的“UI 值”片段,对应到 wxml 的 template, 比如上文 getX 里面的 UI


<template name="template001">    <text>Hello</text></template><template name="template002">    <Container>...</Container></template><template name="template003">    <Center>...</Center></template>
复制代码


  1. 在遇到 类似 x 这种动态值的时候,固定地会生成一个 template 占位。


<template name="template004">    <Center>        <template is="{{templateName}}" data="{{...templateData}}"/>    </Center><template name="template003">
复制代码


  1. 在运行阶段,会根据 getX 函数的运行结果来决定 x 映射的“UI 值”,如果 getX 里面 condition1 为 true,那么这里的 templateName 的值就是 template001*。*具体的数据计算收集工作,参考下面要的 “渲染数据收集”过程。


可以看出 flutter_mp 处理“值 UI”方式,完全参考了 Alita。

渲染数据收集

wxml 结构的生成是在编译阶段就完成了,与它不同渲染数据是运行时的信息,随时会根据 setState 而改变。那么我们怎么收集出我们需要的渲染数据呢?


如果我们还是顺着 Flutter 的架构图,很难插入我们收集的钩子函数,另外 Flutter 的这个架构对于小程序来说太重了,下图红框里的这些过程对于小程序的渲染来说并不必要。最后由于最终的代码会被转化为 js,而 Flutter 本身依赖的库里面很多是不支持转化 js 的,比如 dart:ui 等等。



所以我们实现了一个极简极简的 Flutter 小程序版本 mini_flutter,在编译期我们会把所有对 Flutter 库的引用替换为 mini_flutter, mini_flutter 只存在到上图的 Rendering 阶段,这个 Rendering 的实现也是为小程序定制的, 在运行时期 Rendering 不断收集 Widgets 的信息。最终生成一个 UI 描述的 JSON 结构,这个结构就包含了上文所说的 templateNametemplateData,UI 描述将会被下层小程序获得,用来渲染小程序 UI,架构图如下:


Dart/JS:转化与互操作

Flutter 的开发语言是 Dart,而小程序的运行环境是浏览器,所以我们还需要把 Dart 编译为 JavaScript 代码。


在上文的编译打包阶段也提到这一点,这个过程主要是使用了 Dart 提供的 dart2js 工具,不过,针对小程序环境,生成的 js 代码仍需要做一些适配,另外虽然都是 JS 代码,dart2js 生成的 js 和小程序原生 js 的运行环境却是隔离的,也就是说它们是不能共享变量,方法等等,它们各自在本身的"域"里执行。


这带来两个问题:


  1. Widget 初始化 或者 setState 更新,生成的 UI 描述 JSON,如何传递给小程序"域"呢?

  2. 相关渲染回调,事件的都发生在小程序"域",这些信息如何传递给 Dart?


总结一下:Dart(最终会编译为 JS)与小程序原生 JS 如何互操作?


解决这个问题主要是借助 dart:js, package:js 这两个库:


Dart 操作 JS:


import 'package:js/js.dart';
@JS("JSON.stringify")external stringify(String str);
复制代码


这样当 Dart 代码调用 stringify 方法的时候,实际上会执行window.JSON.stringify方法


JS 操作 Dart:


// dart注册void main() {    context['dartHi'] = () {        print('dart hi!');    };}
复制代码


// js 调用window.dartHi()
复制代码


这里只是简单说明 Dart 与 JS 的互操作,另外由于小程序的运行环境是阉割以后的浏览器环境,flutter_mp 的实现还稍有不同。


总之,Dart 与 JS 是可以互操作的,这样就打通了上层 Flutter 环境和下层小程序环境。

布局系统

Flutter 的布局系统不同与 css,但是和 css 颇相似。



在上文提到的 Rendering 阶段,会根据 Widget 的布局属性,类别,约束条件生成一个等效的 css 样式。注意这里边界约束是上下文相关的。比如一个没有宽高的 Container 实际大小,不仅和子元素相关,还和父元素传递过来的边界约束条件相关,这个其实是比较麻烦的,能不能把 Flutter 的 Widget 属性,边界约束完全用 css 表达,我们还在寻求有效的方案。

总结

flutter_web 一样,完全把 Flutter 所有特性渲染到小程序上是不可能的,一般我们觉得应该是部分页面,部分功能需要运行在小程序上,这样使用 flutter_mp 才是有意义的。


正如前文所说,flutter_mp 还在很早期的阶段,社区的支持和反馈对我们来说特别宝贵。同时欢迎广大开发者一起来维护flutter_mp


如果你需要在生产环境实现小程序跨端开发,推荐使用我们成熟的 RN 转小程序项目Alita


2019-09-27 14:114807

评论

发布
暂无评论
发现更多内容

Kubernetes云原生实战:分布式GeaFlow实现图研发,构建第一个商业智能应用

TuGraphAnalytics

Kubernetes 云原生 k8s BI 商业智能

数智化底座正在成为当前竞争的焦点

用友BIP

数智底座

企业如何落地DevOps(下)

老张

DevOps 软件工程

SpringIoc容器之Aware | 京东云技术团队

京东科技开发者

spring aware springloc Aware 接口 企业号 7 月 PK 榜

使用第一性原理思维思考如何打造提高生产力的平台 | 京东云技术团队

京东科技开发者

数字化转型 平台工程 企业号 7 月 PK 榜

华为Mate X3、P60系列用户隐藏福利:唤醒小艺解决相册搜图难题

最新动态

DataBuff 如何结合 Opentelemetry 监控 golang 应用

乘云 DataBuff

云原生 APM 可观测性 应用性能监控 智能运维AIOps

怎样实现纯前端百万行数据秒级响应

EquatorCoco

前端 表格控件

从大数据到图计算-Graph On BigData

TuGraphAnalytics

GitHub 大数据 开源 图计算 GeaFlow

Unity JobSystem使用及技巧

快乐非自愿限量之名

Unity 教程

体系完整的数智化底座支撑企业创新发展,实现国产替代

用友BIP

国产替代

CST电磁仿真软件配置的CPU、内存、显卡显存越大越好吗?

思茂信息

cst cst使用教程 cst操作 cst电磁仿真 cst仿真软件

TDengine“露面”中国油气田企业智慧油田技术交流大会,为时序数据处理带来全新思路

爱倒腾的程序员

涛思数据 时序数据库 ​TDengine

我感兴趣的技术四剑客 | 社区征文

法医

前端 年中技术盘点

华为云GaussDB亮相2023可信数据库发展大会,荣获三项评测证书!

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

云原生K8S精选的分布式可靠的键值存储etcd原理和实践

不在线第一只蜗牛

云原生 k8s etcd

APP流水线测试领域探索与最佳实践 | 京东物流技术团队

京东科技开发者

测试 app测试 app自动化测试 企业号 7 月 PK 榜

论文解读|TuGraph Analytics 流式图计算论文入选国际顶会 SIGMOD

TuGraphAnalytics

大数据 论文 图计算 SIGMOD GeaFlow

2023开放原子全球开源峰会,蚂蚁图计算平台开源业内首个工业级流图计算引擎

TuGraphAnalytics

GitHub 开源 图计算 蚂蚁 GeaFlow

构建学生数据库

猫九

数据库·

如果我是一个小白,怎么开发网页

猫九

前端

Mybatis-SQL分析组件 | 京东云技术团队

京东科技开发者

mybatis sql mybatis入门 企业号 7 月 PK 榜

SolidUI AI生成可视化,开创性开源项目,版本0.1.0 功能讲解

李孟聊AI

Web 2D 3D AIGC ChatGPT

谁在以太坊区块链上循环交易?GeaFlow+Kafka的0元流图解决方案

TuGraphAnalytics

区块链 以太坊 kafka 图计算 GeaFlow

持续推进平台化、生态化用友助力数智化安全有效落地

用友BIP

信创 国产替代

网心科技入选2023年“边缘计算技术创新先锋案例”

网心科技

边缘计算 边缘云 AIGC

多领域应用落地,火山引擎ByteHouse加速云数仓升级

字节跳动数据平台

掌握 Dubbo:入门教程

Apifox

程序员 gRPC dubbo RPC 开发

全新技术驱动预算管理全面升级

用友BIP

全面预算

从混沌到秩序的蜕变,SRE解码云计算运维奥秘

鲸品堂

云计算 SRE SRE实践 企业号 7 月 PK 榜

浅谈业务级灾备的架构模式

得物技术

运维 稳定生产

京东:将Flutter扩展到微信小程序端的探索_大前端_严康_InfoQ精选文章