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

[译]Hummingbird:构建FlutterWeb应用

https:medium.comflutter-iohummingbird-building-flu

在今天的Flutter Live上,我们宣布正尝试在Web上运行Flutter。在这篇文章中,描述了我们如何应对尝试过程中遇到的挑战以及当前该技术的状态。在本文的最后,您将找到有关互操作和嵌入的问题及答案;

[译] Hummingbird: 构建Flutter Web应用

让我们快速回顾一下Flutter的架构。 Flutter是一个多层系统,更高的层级更方便开发者使用及操作,并允许开发者用更少的代码完成更多的功能,而较低的层级虽然为开发者提供更多的控制能力,然而这种控制也是有代价的:开发者必须处理一些更复杂的事项,当较高层不能满足开发人员的需求时,他们可以深入到较低层。开发人员可以访问Flutter Engine上方的所有层代码;

[译] Hummingbird: 构建Flutter Web应用

Flutter 移动端架构

Flutter Engine作为Flutter暴露出来的最底层库,比如dart:ui。它对widgets,物理模拟(如重力等),动画或布局(文本布局除外)一无所知。它所知道的是如何将图片组合到屏幕上并将它们变成像素呈现。在dart:ui上直接编写应用程序是很困难的,这就是我们为开发者创建更高层的原因;

dart:ui之上的层级就是我们所谓的“框架”层。它下面的层级我们称之为“引擎”。该框架完全使用Dart编程语言编写。大多数引擎都是用C ++编写的,特定于Android的部分用 Java 编写,而iOS特定的部分用Objective-C编写。 dart:ui中的一些基本类和函数是用Dart编写的,主要用作Dart和C ++之间的桥梁。

Flutter还提供系统插件。插件是用一种语言编写的代码,它可以直接访问移动生态系统的OEM库和第三方库。要为Android创建插件,您可以使用Java或Kotlin编写代码。 iOS插件是使用Objective-C或Swift代码编写的。

Hello, The Web

Web平台已经发展了数十年,包括许多技术和规范。有一些术语用于描述相关功能:HTML,CSS,SVG,Javascript,WebGL。为了在Web上运行Flutter,我们需要:

  • 编译Dart代码:Flutter是用Dart编写的,我们需要在Web上运行Dart

  • 选择要在Web上运行的Flutter子集:在Web上运行所有Flutter代码是不切实际也是毫无帮助的。其中一些是特定于具体平台的,例如Android和iOS。

  • 选择足够的Web功能子集:随着时间的推移,Web平台会累积功能重叠的功能。例如,您可以使用HTML + CSS,SVG,Canvas和WebGL绘制图形。

从Dart语言诞生起,Dart语言就可以被编译成Javascript语言。许多重要的应用程序从Dart编译为Javascript,并已经被投放到生产环境中运行。 Flutter的编译策略依赖于同样的基础设施。

当我们开始探索时,我们面临着UI渲染的几种选择。我们很快意识到我们想要支持的特定Flutter层决定了我们将采用何种Web技术实现。我们制作了三个原型:

  1. 只是Widgets:这个原型实现了Flutter的Widget框架,并提供了一组核心布局Widget作为构建自定义Widget的基础。对于布局和定位,它依赖于Web的内置功能,例如flexbox,网格布局,浏览器滚动等。

  2. Widgets+自定义布局:此原型包括Flutter的布局系统(由RenderObject提供),但将渲染对象直接映射到HTML元素。

  3. Flutter Web Engine:这个原型保留了dart:ui之上的所有层,并提供了一个在浏览器中运行的dart:ui实现;

Flutter最有价值的功能之一是它可以跨平台移植。您可以(我们鼓励您)编写自定义平台特定代码,该代码可以共享到各跨平台而不需要有任何差别。这允许使用单个代码库编写面向多个平台的应用程序;

在尝试将几个示例应用程序移植到Web之后,我们意识到原型#1和#2不能提供Flutter开发人员喜欢(可接受)的可移植性级别。因此,我们决定使用原型#3:Flutter Web Engine,因为这将允许最高的框架级代码在不同平台之间重用:

[译] Hummingbird: 构建Flutter Web应用

Flutter for the Web Architecture (Hummingbird)

既然知道了我们想要实现整个dart:ui API,我们需要选择一组Web技术来构建。 Flutter一次呈现一帧UI。在每一帧内,Flutter构建Widget,执行布局,最后在屏幕上绘制它们。

创建Widgets

Widget的构建机制不依赖于应用程序运行的环境。该过程只需要实例化内存中的对象并跟踪它们的状态,当状态改变时,计算布局和绘画所需的最小更新。将此部分移植到Web上非常简单,当Dart团队在dart2js中实现了super-mixin支持之后,编译器将所有widget和widget框架编译为Javascript时几乎没有任何问题;

布局

布局系统有点棘手。最大的挑战是文本布局。其他所有Widget - Center,Row, Column, Stack, Scrollable, Padding, Wrap等 - 这些widget都由框架布局,因此无需修改即可编译到Web上运行。

在Flutter中,您可以通过创建Paragraph对象并调用其layout()方法来放置一段文本。不幸的是,Web缺少直接的文本布局API。我们用来测量文本布局属性的技巧是让浏览器将其布局,然后从DOM元素中读回相关属性。

放置文本段落时,Flutter测量段落的高度,宽度,最大内在宽度,最小内在宽度以及字母和表意基线(下图黄色虚线)。这些属性如下所示。

[译] Hummingbird: 构建Flutter Web应用

Paragraph layout attributes

您可以在Flutter的段落文档中找到更多详细信息。

要测量这些属性,我们首先在HTML DOM元素中放置一个段落,然后我们读取元素的尺寸。这会导致浏览器将其布局。例如,要获取元素的宽度和高度,我们调用offsetWidth及offsetHeight。为了测量基线,我们将段落放置在一个元素中,该元素配置为使用flex row进行自我布局。在段落旁边,我们放置另一个名为“探针”的元素。因为探针与文本的基线对齐,所以调用 getBoundingClientRect 就可以得到基线。我们使用类似的技巧来测量最小和最大固有宽度。

Painting(绘制)

最后但同样重要的是,我们需要绘制上述这些Widgets。我们在这方面的探索经历了很多误区,它仍然是我们研究中最活跃的领域之一。在帧渲染结束时,我们所有的widgets都需要在屏幕上变成像素。在浏览器中,这意味着它们必须归结为HTML / CSS,Canvas,SVG和WebGL的某种组合。

我们还没有看过WebGL,主要是因为它是较底层级别的,并且要求我们重新实现浏览器已经可以做的事情,例如文本布局和光栅化2D图形,也因为我们还没有弄清楚如何使用非Flutter组件的可访问性,文本选择和合成可以与WebGL一起使用。

我们的早期原型之一就是为每个RenderObject生成了一个HTML元素。我们确实获得了有希望的结果,但结果却证明了API的变化太大了。我们必须用Flutter维持一个巨大的代码增量,所以我们搁置了这个想法。

我们目前正在同时探索的两种方法:

  1. HTML+CSS+Canvas的组合

  2. CSS Paint API

HTML+CSS+Canvas

通过这种方法,我们将框架生成的图片分类为使用HTML + CSS表达的图片,以及使用Canvas 2D表达的图片。然后,我们输出结合了HTML,CSS和2D画布的HTML DOM。

我们更喜欢HTML + CSS,因为它有浏览器的显示列表支持。这意味着我们可以优化图片的光栅化在浏览器上的渲染引擎。这也意味着我们可以应用任意变换,尤其是旋转和缩放,而不必担心像素化。我们将此画布实现称为“DomCanvas”。

如果我们无法使用HTML + CSS表达图片,我们会回到画布。 Canvas 2D允许我们绘制几乎所有的Flutter绘图命令。如果将Flutter的Canvas与Web的 CanvasRenderingContext2D 进行比较,您会发现许多相似之处,在画布上绘画是高效的,因为它不会创建需要随时间维护的可变树节点,如HTML DOM或SVG。

2D画布的一个挑战是浏览器将其表示为位图,即存储宽度x高度像素的内存缓冲区。因此,缩放画布会导致像素化。如果缩放导致图片大小的变形,我们需要调整画布大小。我们发现分配画布相当昂贵,因此调整它们的大小。最重要的是,当将多个画布合成到同一页面上时,浏览器必须执行栅格合成,合成栅格与显示列表的工作方式不同。您可以将多个显示列表绘制到同一个内存缓冲区中。我们调用Canvas 2D支持的canvas实现BitmapCanvas。我们正在研究使位图画布更有效的方法。

为了表达Flutter的 opacity, transform, offset, clip rect和其他图层,我们使用纯HTML元素。例如,不透明度层变为元素,其上具有不透明度CSS属性,变换层变为带有变换CSS属性的元素,而clip rect变为带有overflow:hidden的

完成所有操作后,帧将被渲染在作为HTML元素树的页面上呈现,其中DomCanvas和BitmapCanvas作为叶节点。例如:

Sample HTML DOM structure of a frame

Flutter Engine中的等效Flutter层级树(称为 流层 )如下所示:

Sample Flutter Engine layer structure

在结构上它们非常相似。最大的区别是,在Web上,我们必须根据内容选择不同的图片实现。

HTML + CSS + Canvas适用于所有现代浏览器。但是,我们已经在展望未来:

CSS Paint API

CSS Paint是一个新的Web API,是Houdini的一部分。 Houdini是指许多浏览器供应商之间的合作,旨在向开发人员展示CSS引擎的某些部分。特别是,CSS Paint API允许开发人员在这些元素请求绘制时将自定义图形绘制成HTML元素。例如,您可以将元素背景的绘制任务分配给自定义CSS 画笔(painter)完成。它与canvas非常相似,但有以下重要区别:

  • 这个绘画不是由主要的Javascript独立完成的,而是由一个叫做paint worklet的东西完成的。它有自己的内存空间,在提交DOM更改之后,在浏览器的绘制阶段执行绘制工作。

  • CSS绘制由显示列表支持,而不是位图。这给了我们两全其美的好处 - 兼顾2D画布般的绘画效率和没有像素化。

  • 目前CSS绘画不支持绘画文本。

在撰写本文时,Chrome和Opera是目前仅有的支持CSS Paint的浏览器。但是, 其他浏览器处于实现过程中的各个阶段 。

我们在Web上运行Flutter中的CSS Paint API得到了实验性支持,它已经显示出良好的结果,特别是在性能方面。我们的实现只是将paint命令序列化为自定义CSS属性。paint worklet读取这些命令并执行它们。我们使用普通的

HTML元素渲染文本。

我们当前的序列化机制不是特别有效 - 它是一个将嵌套列表转换为JSON的树 - 但一部分Houdini项目的作法是添加对类型化数组的支持。要让它变成可用的话,我们需要将绘制命令编码为类型化数组而不是JSON字符串。类型化数组是可转移的,这意味着它们可以通过引用从主隔离传递到paint工作,这个操作不涉及复制内存。

Interop and embedding(互操作及嵌入)

从Flutter调用Dart库

Flutter Web应用程序可以完全访问当今在Web上运行的所有现有Dart库。

从Flutter调用Javascript库

Flutter Web应用程序完全支持Dart的JS-interop包:package:js和dart:js。

在Flutter Web应用程序中使用CSS

目前,Flutter假设完全控制网页的正确性和性能。例如,我们只使用遵循某些性能指南的一小部分CSS,例如csstriggers.com/。在页面上放置任意CSS可能会导致Flutter表现不可预测。

另一个在Flutter Web应用程序中避免使用CSS的原因是,在设计时,Flutter需要在渲染帧时知道所有布局属性。 CSS充当黑盒子的角色。例如,如果要显示可滚动的widget列表,则必须实例化并为所有widget生成HTML并应用必要的CSS属性(例如,flex-direction row和overflow:scroll)。然后浏览器将所有内容都放置排列出来并将其呈现在屏幕上。应用程序代码不参与布局过程。

最后,本着保持Flutter代码可跨平台移植的精神,我们避免使用CSS,因此我们可以在Android和iOS上运行相同的代码。

将Flutter嵌入现有的Web应用程序中

我们还没有为此添加适当的支持,但我们打算在将来进行探索。我们正在考虑的几种方法是使用和shadow DOM。

在Flutter中嵌入非Flutter组件

我们还没有添加对在Flutter Web应用程序中嵌入非Flutter组件 - 自定义元素,React组件,Angular组件 - 的支持,但我们打算在将来探讨这一点。一种可能的途径是使用平台视图将外来内容放入Flutter Web应用程序中。需要考虑的一个重要方面是这些外来内容可能对应用程序的性能和正确性产生何种影响。因为非Flutter组件可能包含任意CSS,如上所述,它可能会有问题。需要更多的研究。

可移植性

我们的目标是尽可能多地将flutter框架移植到Web上。但是,这并不意味着任何Flutter应用程序可以不用更改代码就可以在Web上运行。Flutter Web用程序仍然是一个Web应用程序;它在浏览器中被沙箱化,只能执行Web浏览器允许的操作。例如,如果您的Flutter应用程序使用到了没有Web实现的Native 插件,例如ARCore,您将无法在Web上运行该应用程序。同样,它也没有直接访问文件系统或底级网络的权限。

当前状态

我们构建了足够的Web引擎来渲染大部分Flutter Gallery示例中的内容。我们还没有移植Cupertino Widget,但所有Material Widgets,Material Theming,以及Shrine和Contact Profile演示应用程序都已经可以在Web上运行。(演示视频地址)

源代码放置在何处?

我们计划很快开源这个项目,并很高兴与开源社区分享。该项目最初是作为Google内部源代码树的一项探索而开始的。我们的代码稳定后,我们打算将开发转移到GitHub,我们有机会将其与内部基础架构分开,与此同时,如果您在 github.com/flutter 看到与Web相关的拉取请求,请不要感到惊讶!

结论

我希望这篇文章能让您了解到我们正在解决的问题,以使Flutter在Web上良好运行。我们欢迎您的想法和主意。 请继续关注Google I / O 2019!

原文链接

https://medium.com/flutter-io/hummingbird-building-flutter-for-the-web-e687c2a023a8

转载请注明出处

Email:linguowu0622@gamil.com

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 我们


推荐阅读
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 本文介绍了腾讯最近开源的BERT推理模型TurboTransformers,该模型在推理速度上比PyTorch快1~4倍。TurboTransformers采用了分层设计的思想,通过简化问题和加速开发,实现了快速推理能力。同时,文章还探讨了PyTorch在中间层延迟和深度神经网络中存在的问题,并提出了合并计算的解决方案。 ... [详细]
  • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 小程序自动授权和手动接入的方式及操作步骤
    本文介绍了小程序支持的两种接入方式:自动授权和手动接入,并详细说明了它们的操作步骤。同时还介绍了如何在两种方式之间切换,以及手动接入后如何下载代码包和提交审核。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
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社区 版权所有