Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践,欢迎一起交流探讨。
Flutter是Google开源的一套UI工具包,帮助开发者通过一套代码库高效构建多平台精美应用,支持移动APP、web、桌面和嵌入式平台。Flutter和其他的跨平台的解决方案的实现方式上有比较大的差异。
我们以React Native(下文简称RN)跨平台解决方案为例。在RN中,开发者使用JavaScript(JS)语言来开发,中间会有一层桥接层(Bridge),桥接层的主要作用就是提供一套完整的接口,使得JS代码可以直接使用移动端提供的UI组件和相关的API方法,并通过将这些组件进行组合,来最终实现整个页面的展示。
React Native跨平台解决方案
Flutter却并没有使用移动端平台提供各种UI组件,而是将UI组件的具体实现上移到Flutter的Framework层中,然后调用平台提供的底层绘制引擎来直接绘制在Framework中生成的各种UI组件。这样可以在最大程度上保证同一套代码在不同平台、不同设备的UI展示和用户体验的一致性。不过除了UI绘制以外,Flutter在其他的原生能力的桥接上面和其他的跨平台方案基本类似。
Flutter跨平台解决方案
在Flutter的整个解决方案中,Flutter For Web和Flutter For Mobile的实现方式上又有些不同。因为Flutter For Web是需要最终嵌入到浏览器中进行绘制和展示的。因此它的很多能力依赖于浏览器对外提供的接口和能力。但是和iOS、Android不同,浏览器并没有提供一套广泛使用、完备、高效的绘制接口,这就使得Flutter For Web和Flutter For Mobile在架构上还是有比较大的差别的。
Flutter For Web的目的就是想要在单代码库的情况下,使Flutter拥有Web支持的能力。这样使用Flutter开发的应用不但能部署到iOS、Android手机上,还可以部署到任意的Web服务器上、嵌入到浏览器中,而不需要特殊的浏览器插件的支持。
Flutter For Web和Flutter For Mobile的上层实现基本类似,但是在下层的实现有很大的差别。Flutter For Mobile中的绘制是使用了Engine中的Dart、Skia和Text然后再调用iOS和Android提供的底层绘制能力来实现的。
Flutter For Mobile
对于浏览器环境,没有提供一套完备的绘制接口,因此在绘制过程中,会使用Cavans、Dom或者两者混合的方式来进行绘制。
Flutter For Web
在Flutter For Web的实际的开发和绘制流程中,首先开发者使用是Dart语言来进行开发,开发完毕在编译的过程中会通过dart2js的库,将dart实现的代码转换成对应的js代码。在js代码中,会将一些简单的可以通过HTML和CSS来实现的UI组件通过HTML和CSS来进行绘制,而一些复杂的UI组件则会使用Canvas来直接进行绘制,然后通过生成Dom树,最终在浏览器中进行渲染。
但是由于很多复杂的组件在dart2js的转换过程中难以使用HTML+CSS来进行绘制,因此会导致很多组件最终是直接通过Canvas绘制的,因此这也会导致使用Dart开发的Web应用在效率上会存在一些问题。这也是Flutter For Web现存的一个问题,官方也一直在优化和寻找解决方案过程中。
在开发过程中如何使用一套代码来既兼容Flutter For Mobile又兼容Flutter For Web呢?
首先需要 master 或者 dev 渠道的的 Flutter SDK 来获取 Web 支持。
创建一个名为myapp的应用。
编译当前应
flutter build web目增加对flutter web的支持
如果在已经有的项目中增加对Flutter For Web的支持,则需要以下命令:
对于增加了对Flutter For Web支持的Flutter应用,他在代码目录中增加了一个Web文件夹,其中包含 index.html 文件是整个Web应用的入口。其中他引用了一个JS文件是main.dart.js,但是我们在工程目录中是找不到这个文件的。其实这个文件是我们的Flutter工程编译后生成的js文件,如果我们曾经编译成功过这个工程,会在编译后的build文件夹中看到这个js文件。
和普通的Flutter应用一样,主要的功能实现还是在工程中的lib文件夹中。但是如果你需要有资源文件、js 文件等 web 所需资源,可以放到Web这个文件夹中。
Flutter For Web应用编译后的产物位于build文件夹下的web目录中。其中assets和icon文件夹中是Web应用的资源文件。index.html 文件,是整个Web应用的入口,而main.dart.js是dart代码编译后产生的js文件。
其中的main .dart.js大小是2.6M,对于一个功能不是特别复杂的web应用来说,2.6M来说是很大的一个JS库了。因此首次加载的时候,可能会需要很长的时间,这也是官方需要进一步优化的地方。
1.有部分库在Flutter web中不支持
比如:dart.io无法在web中使用,dart.io支持非web应用程序的文件、套接字、HTTP 和其他 I/O 操作。
2.有部分库只能Flutter web中使用
比如:dart:html是关于html 相关的操作的库,如 document、ua、cookie 等;
比如:dart:js是dart 和 JS 进行交互的库,可以给 js 方法传参,甚至还可以将 js 的参数带回等等;
因此这就会给我们通过一套代码来实现多平台的兼容,带来了不少的挑战。
我们可以通过使用条件引用来解决这个问题,比如下面的代码中,我们对移动端和web端的网络请求分别实现是两个文件中httpReuqest-mobile.dart和httpReuqest-web.dart,如果当前的平台支持dart.library.html也就是web端,就会引入httpReuqest-web.dart文件中的网络请求的实现,而如果当前的平台支持dart.library.io也就是移动端平台,就会引入httpReuqest-mobile.dart文件中的网络请求的实现。
虽然使用Fluter进行web开发和进行移动端开发在绝大多数情况下没什么区别,但是两者在开发中还是有不少需要注意的地方。
现在支持Flutter web的第三方库相对较少,绝大多数的库还是暂时只支持移动端开发。
Flutter web中的Cookie管理实际上是由浏览器来管理的,因此无法像客户端开发一样,自由的设置cookie。
跨域访问的问题:一个web页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。因此,与客户端不同,web原则上只能请求本域名的网络接口,除非该接口设置可以接受跨域访问。
Flutter For Web 目前都是单页面应用。最简单的web应用编译后main.dart.js 的大小也会轻松过 1M,这可能会导致首次加载可慢。其次,因为页面中的很多组件其实是使用 canvas 直接绘制,和通过HTML+CSS的web应用相比绘制的速度也会变慢,从而导致性能问题。PC 端首次加载的速度略慢,而手机端会有超过 2S 的延迟。复杂列表滑动的时候帧率也只有十几,所以这里还有待官方后面对性能进行优化。
示例网站:https://dev.kuyichang.com/,https://rive.app/ Hello from i校长 | i校长
作为一种还在不断完善和发展的技术,Flutter For Web还是值得期待的。
优点:
l 一个代码库可以同时支持手机端和Web端
l 自适应的布局
l 支持PWA
l 绝大多数的官方组件支持Web
l 降低人力成本提高开发效率
缺点:
l 性能问题,虽然在不断的优化
l 对SEO并不友好
l 社区比较小,开发者较少
l SDK体积大加载时间长
l 调试比较困难
Flutter For Web还有许多需要Google进行优化和完善的地方,
1.对不同浏览器的支持
chrome、safari、firefox、ie/edge等不同的浏览器对各种不同的协议支持的程度都不一样而且有些还有自己的特有的接口和协议,如何能兼容各种不同的浏览器对于Flutter For Web是一个不小的挑战。
2.性能的优化
首先编译后的JS大小包括后续JS的分包加载等
其次渲染效率的提升
3.生态的完善
Flutter第三方库对于Web的支持对于Flutter For Web的发展也是至关重要的。
当然每一种技术都有它的使用范围,谷歌推荐使用flutter web的场景有Progressive Web Apps(PWA)、Single Page Apps(SPA)以及现有app迁移。如果解决好以上的问题,相信Flutter For Web在上面的这些领域的开发上应该能获得一席之地。
作者:郝宏伟