热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

点击上方“开发者技术前线”,选择“星标”13:21在看真爱作者:严康京东ARES来自|:前端之巅ARES作为京东技术中台的多
点击上方“开发者技术前线”,选择“星标”
13:21 在看 真爱

640?wx_fmt=jpeg

作者:严康 京东 ARES   来自|:前端之巅
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 的实际效果:

640?wx_fmt=png

Flutter 版官方 layout 样例

640?wx_fmt=png

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

声明式 UI 的处理

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

我们看一个最简单例子:

var x = 'Hello World'Center(child: Text(x)
);

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

// wxml 部分

{{x}}
// js 部分
Component({data: {x: 'Hello World'}
})
虽然实际的结构要比上面的情况复杂的多,不过通过上面简单的例子,我们知道起码要做两个事情:
  1. 我们需要根据Flutter代码生成相关小程序 wxml 模版文件。
  2. 收集 wxml 渲染需要的数据,放置到小程序组件的 data 字段。

wxml 结构生成

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

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

640?wx_fmt=png

构建 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 &#61; getX();Center(child: x // <--- 如何处理这里的 x&#xff1f;&#xff1f;
);

这里的 child: x&#xff0c;x 是一个动态值&#xff0c;它的具体值需要在运行阶段才能确定&#xff0c;它可能是任意的 Widget&#xff0c;如何在静态的 wxml 上处理这里动态的 x&#xff1f;受 Alita 框架的启发&#xff0c;这里主要是借助于小程序 template 的动态性&#xff08;template 的 is 属性可以接受变量值&#xff09;。有如下几步&#xff1a;
  1. 首先在遍历 Dart 源码 AST 结构的时候&#xff0c;会把每一个独立完整的“UI 值”片段&#xff0c;对应到 wxml 的 template&#xff0c; 比如上文 getX 里面的 UI。

Hello

...

...

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


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

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

渲染数据收集

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

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

640?wx_fmt&#61;png

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

640?wx_fmt&#61;png

Dart/JS&#xff1a;转化与互操作

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

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

这带来两个问题&#xff1a;
  1. Widget 初始化 或者 setState 更新&#xff0c;生成的 UI 描述 JSON&#xff0c;如何传递给小程序"域"呢&#xff1f;

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

总结一下&#xff1a;Dart&#xff08;最终会编译为 JS&#xff09;与小程序原生 JS 如何互操作&#xff1f;

解决这个问题主要是借助 dart:js&#xff0c; package:js 这两个库&#xff1a;

Dart 操作 JS&#xff1a;

这样当 Dart 代码调用 stringify 方法的时候&#xff0c;实际上会执行window.JSON.stringify方法。

JS 操作 Dart&#xff1a;

// js 调用
window.dartHi()

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

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

布局系统

Flutter的布局系统不同与 css&#xff0c;但是和 css 颇相似。

640?wx_fmt&#61;png

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

总结

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

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

flutter_mp: https://github.com/areslabs/flutter_mp

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

Alita&#xff1a;https://github.com/areslabs/alita

后台回复 “666” 即可领取程序员大礼包
END


开发者技术前线 &#xff0c;汇集技术前线快讯和关注行业趋势&#xff0c;大厂干货&#xff0c;是开发者经历和成长的优秀指南。
历史阅读






640?


640?wx_fmt&#61;png
在干货 大家一起看


推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • 本文介绍了自学Vue的第01天的内容,包括学习目标、学习资料的收集和学习方法的选择。作者解释了为什么要学习Vue以及选择Vue的原因,包括完善的中文文档、较低的学习曲线、使用人数众多等。作者还列举了自己选择的学习资料,包括全新vue2.5核心技术全方位讲解+实战精讲教程、全新vue2.5项目实战全家桶单页面仿京东电商等。最后,作者提出了学习方法,包括简单的入门课程和实战课程。 ... [详细]
  • Question该提问来源于开源项目:react-native-device-info/react-native-device-info ... [详细]
author-avatar
帅气小子勇哥
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有