Flutter for Web 详细预研

Stella981
• 阅读 546

背景

Google在最新的Google I/O上推出了Flutter for Web,旨在进一步解决一次代码,多端运行的问题。Flutter for Web还处于早期试验版,官方不建议在生产环境上使用。那么到底它的实际情况怎么样呢? 我们做了一次预研。期望这次预研的结果可以帮你决定是用,还是不用FFW。

Flutter for Web原理

Flutter for Web 详细预研

Flutter for Web和Flutter在上层都是Dart环境,两者不同的是,Flutter的Dart代码运行在Dart虚拟机中,界面由Flutter引擎处理,通过Skia绘图引擎经由GPU绘制到屏幕上。而Flutter for Web的Dart代码编译成JavaScript,界面上部分转换成标准的html标签,部分转换成通过Canvas绘制的自定义标签,最终构成一个dom树。
这个原理上的差异非常重要,这直接可以让我们通过原理得出下面的结论:

Flutter for Web的一致性和体验上存在矛盾

如果Flutter for Web追求(和Flutter)完美的一致性,势必需要大量使用Canvas去绘制,而Canvas去绘制组件的性能(尤其在移动端)至少不会比html标签好。如果FFW追求性能极限而使用大量标准的html标签,这就会带来和Weex、RN等一样的一致性问题:对于Flutter所有的控件都是一套代码在绘图引擎上绘制,对Flutter for Web如果要使用大量html标签,那如何保证一致性呢?只能靠大量精细的打磨工作了。所以FFW必须要处理好这个平衡。

为啥使用canvas绘制性能不优于手写html呢,定性的从几个角度分析:

  1. FFW在canvas上绘制的组件带有很多MD特色的视觉和动画,比如阴影、Z轴变化等,这部分对性能的消耗要大于普通html标签
  2. FFW是通过Dart的DSL转成的dom树结构,转化后的dom树十分复杂,不太可能比手写的dom树更简洁
  3. 使用canvas的控件,其手势事件的捕获分发都是靠FFW框架自己实现的,emmmm
    虽然不排除Google大力出奇迹的情况,但是不管怎样,相同素质的开发人员,相同的界面,性能上也不可能优于html+css+js

另外一点,如果FFW在原理上涉及大量HTML标签的转化,那就势必会涉及到碎片化的处理中,浏览器的碎片化程度可一点都不比Android系统的碎片化小。像Flutter本身之所以被那么多人看重,就是因为其通过绘图引擎这一层,完美的避开了碎片化,保证一致性。
所以最好的平衡就是,只有有限的一部分标准的html标签可以被FFW复用,其必须有几点性质:

  1. 标签本身的功能简单又直观
  2. 最好不要有直接图形化的展示,或者只负责简单的图形化展示(比如画方形)
    那几个比较典型的标签就是<p><div>这种了

Flutter官方就是这么做的,所以我的结论是:
一致性上大体不会存在问题,性能上,FFW应该不会优于纯手写html标签界面。

官方现状&建议

根据官网Github repo上的说法,我们整理了一下:

  1. Flutter for Web和Flutter目前暂时是两个仓库,官方正在进行合并,没有给出结论。这一点在工程上非常重要,它说明了几个问题:

    1. 目前官方对FFW的成熟度没有信心,同时FFW的迭代速度也很快。
    2. 目前FFW和Flutter最多保证API一样,实现原理差异可能非常大,同时不保证所有控件都已经在FFW上实现。
  2. 官方不建议应用在生产环境

  3. 目前插件能力十分有限,和系统交互的一些能力缺失,比如拍照等。

  4. 性能无法保证,运行会慢,可能会有掉帧

  5. FFW中针对桌面的UI部分没有完成(跟我无线有什么关系?)

  6. 开发中只能在Chrome中调试(又有什么关系?),release版是可以运行在任意浏览器中(除了IE,另支持的最低版本存疑)。

实践

对于这么新的东西,官网上的内容的确不多,而且简单来看这些问题好像也没什么,所以对于到底能不能用,我们还是需要抱着吃螃蟹的心态具体进去预研一下,为了尽快弄清,我计划找一个我们app已经做好的flutter页面,把它迁移成FFW,对整个迁移过程做个评估,再看下页面效果,基本上就能得出结论了。
具体的迁移细节就不提了,大体上就是这么几个步骤

  1. 安装Flutter for Web的工具webdev
  2. 改SDK依赖,新增Web文件夹(和之前存在的android、ios文件夹同级),新增一些其他文件(index.html, main.dart等)。
  3. 将所有flutter代码中依赖的flutter包,改成flutter_web包
  4. 去掉所有不兼容的代码,比如多语言、路由、Platform.isAndroid等等
  5. 编译运行

实践的主要目的,有以下几个:

  1. 对整体坑的深度和广度有个认知,方便推算出填坑成本
  2. 对FFW整体的性能和体验有个把握,尤其是我们自己的页面跑在FFW上是什么体验。
  3. 对FFW和JS相互调用有具体的了解,如果可行,那复用集团已有能力(比如mtop)的坑就会小很多

Flutter for Web 详细预研

删了一万行代码跑成功之后,最终在工程、开发体验、用户体验上得到一些结论,以下的结论中,体验部分是我在我的mix2s上的感受:

工程

  1. 支持debug和release模式,后者比前者性能高(差异很明显)。

    1. debug模式支持代码修改后自动重新编译,和其他的前端框架(我只用过Django)一致
  2. 支持hotreload,暂时没有尝试

  3. 支持webdev build命令编译出index.html+js,可以通过nginx做反向代理。

  4. 非常重要 编译出来的代码,gzip压缩前,最简单的helloworld的main.dart.js大小约为500k左右,sample中的gallery大小约为2M,阉割版的纯展示用的订单列表大小约为1.3M。gzip对文本的压缩率一般是80%,压缩后也要动辄几百k的大小。而且main.dart.js不加载完,界面是不会展示的。

开发体验

  1. 非常重要flutter for web使用flutter_web库,且不支持其他许多插件,这会带来几个问题

    1. 工程上无法优雅的解决flutter和flutter_web共存的情况,最多搞个dart2的conditional import(这个特性可不在官方文档中哦)
    2. 依赖flutter sdk的几个库,尤其是多语言库无法应用在flutter_web上,并且Google肯定不会再单独为flutter_web适配,而是在合并时做支持。这就意味着现阶段所有依赖flutter sdk的库不能被flutter_web使用。
  2. 调试困难

    1. 错误日志可以打印到浏览器的console中,但是try catch部分的堆栈不好拿
    2. 浏览器中的堆栈很复杂,但是基本上能找到出错的dart代码
    3. 目前没有发现单步调试的能力
  3. Platform.isAndroid全部报错,针对Android和iOS做差异化展示目前还不知道有没有其他方法可以做到。

  4. 目前没有发现控件的api不一致的地方,不过有些控件的行为十分异常,比如下拉刷新,在Android手机上经常卡死、失效。猜测重交互的一些控件都有可能存在类似的问题,但是测一遍的成本太高。

  5. 图片控件NetworkImage可以直接用,但是现在来看有些糊,不确定是官方控件的问题,还是我们做的cdn url策略有问题。

  6. dart代码可以调用js,开发体验和反射类似,并且需要处理JS类型和Dart类型的转换。Dart和JS的交互速度未知。只能说哪怕FFW有很多浏览器的API不支持,也可以通过JS来扩展能力。

  7. Dart和Js语言本身的差异会带来测试和兼容成本的增加,虽然Dart可以编译成Js,但是跑在DartVM上的Dart的表现,和其编译成Js运行在浏览器中的表现并不完全相同。比如对于如下代码

    Map<String, String> query = null;
    val b = query["abc"];
    

    在DartVM中该代码可以执行,结果是b=null;但是编译成Js以后运行时因为query为null,会报空指针。

用户体验

使用了chrome、uc、小米自带浏览器分别试了一下订单列表和官方的sample-gallery界面,体验如下:

  1. 加载速度差不多,因为是局域网环境,感知不到差异。
  2. 非常重要打出的唯一的main.dart.js和部分资源文件(比如MaterialIcons)没有加载出来的时候,界面不会展示。
  3. 帧率或者流畅度上,chrome > uc >> 小米自带浏览器,其中chrome算是最流畅的体验,但是sample中的一些动画和页面转场也可以看到明显的卡顿。
  4. 文字展示上,看flutter for web的界面,chrome对大部分文字处理的很清晰,小米自带浏览器看文字明显模糊。对比下面两张图,点开放大之后查看,FFW页面的文字模糊的很明显。

Flutter for Web 详细预研

  1. 所有浏览器都不能选中文字复制粘贴。flutter for web应该是以canvas处理展示文字的,这样才能解释为啥有的字体size会模糊,并且不能选中文字。

  2. iOS的safari和chrome访问demo页,TextField整个不可用,包括以下问题:

    1. 软键盘弹出逻辑诡异,大部分时候弹出自动缩回,小部分时候正常弹出(Android这部分表现正常);但焦点转移的时候不会自动收回
    2. safari不能输入文字,chrome可以输入(Android这部分表现正常)
    3. 可以选中文字,复制和粘贴不生效(Android问题相同)
    4. 焦点到TextField的时候界面会自动放大,这个时候很难缩放回去(Android这部分表现正常)

总结

按照上面的,整体总结一下,Flutter for Web有几个比较严重的问题,不解决的话估计是无法应用到生产环境上的:

  1. 包大小问题,这会带来几个问题:

    1. FFW的包远大于正常h5的包,对流量和页面加载速度都是很大的挑战
    2. FFW打成一个JS包,多个FFW页面无法对公共组件进行复用,进一步造成浪费。
    3. FFW的js包不加载完,页面无法展示,用户体验极差;而H5可以渐进加载,js可以后入场。
  2. SDK分离的问题,这也会带来几个问题:

    1. 工程上,很难优雅的解决两个SDK并存的问题
    2. 能力上,依赖Flutter SDK的官方库,比如多语言库,不支持FFW SDK。只能自研一套多语言方案。
  3. 表单场景不要用FFW,上述说到的TextField的问题不知能否在应用层去解。

  4. 一些重交互的组件,比如下拉刷新等,存在问题,几乎无法使用。不确定整体组件的质量情况如何,挨个去看成本太大。

结论

  1. 没有非常强的业务诉求或者技术推动,不要在目前尝试在生产环境使用Flutter for Web。
  2. 如果有填坑的决心,并且舍得投入,并且对包大小不关心,对帧率等用户体验也不看重,可以考虑现阶段进行尝试。
  3. 我个人判断填坑成本在100人日以上(上限未知),并且有些坑(包大小)可能根本填不了。
  4. 什么时候可以再次跟进?我认为在FFW合并进Flutter SDK的时候,至于他们具体的规划需要问下Google的人了。

填坑指北

本节的主要目的是列出假设要做FFW,我们需要做的技术项和对应方案。

Flutter for Web 详细预研

原文链接
本文为云栖社区原创内容,未经允许不得转载。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这