HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

京东:将 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:114989

评论

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

SmartZipper for Mac(专业压缩解压工具)v2.10激活版

iMac小白

Tidy Up for Mac(重复文件查找清理工具)v6.0.4激活版

iMac小白

构建企业多维模型,助力财务战略规划

智达方通

战略规划 全面预算 多维模型 财务规划

数仓实践丨从CU入手优化HStore表

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 华为云GaussDB(DWS)

Lights Out for Mac(扩展节能器)v3.2修复激活版

iMac小白

Git 教程:解密 .gitignore 文件、合并分支、解决冲突、及 Git 帮助

小万哥

git 程序人生 编程语言 软件工程 后端开发

CSS图像边框:Interop 2023的一个重点领域

南城FE

CSS 前端 图像边框

Disk Graph for Mac(磁盘空间分析工具)v3.0.2激活版

iMac小白

深入解析Python并发编程的多线程和异步编程

华为云开发者联盟

Python 多线程 开发 华为云 华为云开发者联盟

大厂经验谈之OKR目标管理

巫山老妖

Programming Abstractions in C阅读笔记:p303-p305

codists

抖音详情API:API请求格式与参数详解

技术冰糖葫芦

API 接口

Things3 for Mac(日程和任务管理工具)v3.20中文免激活版

iMac小白

OpenAI和谷歌,AI对线中的飞驰人生

脑极体

AI

docker安装minio

百度搜索:蓝易云

Docker Linux 运维 Minio 云服务器

HTTP/1.1协议中的八种请求

百度搜索:蓝易云

云计算 Linux 运维 HTTP 云服务器

朴素的DevOps价值观

华为云PaaS服务小智

软件开发 华为云

Gateway API与Ingress:Kubernetes网络的未来

Gingxing

kong api 网关 Kong 网关 消息网关 Kong Gateway

Native SQLite Manager for Mac(极简SQLite数据库管理器)v1.27.3激活版

iMac小白

GM CHM Reader Pro for mac(CHM阅读器)v2.5.3激活版

iMac小白

一文搞懂设计模式—享元模式

Java随想录

Java 设计模式

Tower for Mac(强大的Git客户端)v10.4注册激活版

iMac小白

从smallredbook.item_get_video看电商行业的发展趋势

技术冰糖葫芦

API 文档

ubuntu安装指定版本:nodejs

百度搜索:蓝易云

Linux ubuntu 运维 Node 云服务器

李林甫,天才制度大师还是庸才裱糊匠?

酱紫的小白兔

极狐GitLab 16.9 重磅发布,赶快来 pick 你喜爱的功能吧~

极狐GitLab

GraphicConverter 12 for Mac(图片浏览器)v12.1.1(6434)中文激活版

iMac小白

Screen Recorder by Omi Mac(Omi录屏专家‬)v1.3.8激活版

iMac小白

牛刀专业低代码平台开发实战—三会议案

牛刀专业低代码

低代码 起步牛刀低代码 牛刀低代码 牛刀专业低代码 牛刀低代码paas平台

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