Flutter For Web性能优化和新场景探索

发布时间:2025-05-19 01:07:31 作者:益华网络 来源:undefined 浏览量(1) 点赞(1)
摘要:来源:之家技术 背景 近些年随着Flutter开发的App不断涌现,其灵活高效的编程体验、建设良好的开发生态和后期易维护等优点,逐渐得到开发者和企业的认可。 Flutter代码稍作调整,即可同时编译、打包出来App和Web/H5站点。

来源:之家技术

背景

近些年随着Flutter开发的App不断涌现,其灵活高效的编程体验、建设良好的开发生态和后期易维护等优点,逐渐得到开发者和企业的认可。

Flutter代码稍作调整,即可同时编译、打包出来App和Web/H5站点。后者即为Flutter For Web(简写FFW)。例如:若App内嵌了Flutter页面,那么这些页面就可以被重复利用,生成M站。

但是FFW直接产出的Web/H5站点,首屏加载速度普遍较慢。另外,深入使用FFW也会发现,其2种渲染模式在复杂页面的交互上,有不同程度的卡顿问题。

针对上述性能问题的解决,作者做了较为详尽的调研:本文首先分享了性能优化的经验;然后引入element-embedding的概念;最后分享一种探索出的、适用于某些场景的试验方案。

1.渲染模式及性能优化

FFW有2种渲染模式,是由同一套源码,使用2种不同的命令,打包出来的2套编译产物。

1.1

渲染模式介绍

html渲染模式:Flutter采用html的custom element,CSS,canvas和SVG来渲染UI元素。值得注意的是,此模式最终产物的html标签数量十分有限,仍以canvas绘制为核心。这也是导致其不够“浏览器友好”的原因。

canvaskit渲染模式:Flutter将 Skia 编译成 WebAssembly 格式,并使用 WebGL 渲染。此模式必需加载wasm内核文件和noto字体文件。此模式性能表现、浏览器兼容性表现更优秀。若是对首屏速度要求较少的场景,如内部Web系统,建议使用此模式。

1.2

 优化经验(html渲染)

1.2.1首屏速度优化

Icon font裁剪。若项目中使用到了MaterialDesign图标字体库,请使用最新的Flutter SDK,在编译期间自动对字体资源进行了裁剪,并重新生成otf/ttf文件。

gzip开启。若Server端开启gzip,主Javascript文件(main.dart.js)的体积优化将超过1倍。

分片和hash化。主Javascript文件体积较大,可以利用脚本在每次打包之前,将其拆分成n个子文件;在入口处增加逻辑,用户在进入html后,并行下载n个子文件,最后动态组装。

可借助flutter_web_optimizer工具库。打包命令:

flutter build web --web-renderer html --release --pwa-strategy none  

flutter pub run flutter_web_optimizer optimize --asset-base ./

主html优化。利用传统前端优化方法:defer、preconnect和dns-prefetch等属性配置。

 1.2.2 刷新帧率优化

build刷新相关:

局部刷新。目的是减少rebuild范围。在大型、复杂页面的性能优化上,可以利用StreamBuilder或Provider机制,实现局部刷新。

Clean的build方法。不在build方法内进行逻辑计算。通过DevTools性能监测工具,可以发现用户交互操作(如滚动长列表)后,build方法可能被频繁调用。所以build方法越复杂,越可能导致卡顿等性能问题。

多使用无状态的、静态化的Widget。如:若Widget不涉及状态,就封装为StatelessWidget。又如:用得上KeeppAlive模式的Widget,在性能优化的时候,也可以加以使用,以获得Widget的状态保持、减少build刷新。

Scroll组件相关

SingleChildScrollView内嵌Column。若情况为“列表item结构复杂、不统一,且item数量有限”时建议使用。

ListView.builder。若情况为“列表的item结构类似,或长度很长、甚至不限”时使用。其优点是可动态复用item的资源,节省内存开销。

可以采用自定义的“弹簧属性”的physics。自定义的physics可调整滚动的速度、延伸、回弹效果等。

class AhCustomScrollPhysics extends ScrollPhysics 

{

  const AhCustomScrollPhysics({ScrollPhysics? parent}) : super

(parent: parent);

  @override

  AhCustomScrollPhysics applyTo(ScrollPhysics? ancestor) {

    return

 AhCustomScrollPhysics(parent: buildParent(ancestor));

  }

  @override  SpringDescription get

 spring => SpringDescription.withDampingRatio(

        mass: 0.1,   //质量,控制滚动的惯性        stiffness: double.maxFinite, //刚性,滚动收尾速度        ratio: 0.1,  //damping: 0.1, //阻尼,俗称摩擦力

      );

1.3

优化经验(canvaskit渲染)

►1.3.1首屏速度优化

wasm内核处理

在主html里配置canvaskit.wasm加载路径的前缀(最新FlutterSDK支持的功能)。

或者存放在国内CDN并使用url前缀。

否则此文件会从Google的一个外网CDN匹配和下载,国内访问速度较慢。

goCanvaskit = () =>

 {

        console

.log(target);

        _flutter.loader.loadEntrypoint({

            entrypointUrl"./flutter_canvaskit/main.dart.js"

            onEntrypointLoadedasync

 (engineInitializer) => {

                let appRunnerCanvaskit = await

 engineInitializer.initializeEngine({

                    hostElement

: target,

                    canvasKitBaseUrl"./flutter_canvaskit/canvaskit/"//前缀处理

                });

                await

 appRunnerCanvaskit.runApp();

                console.log("canvaskit loaded."

);

            }

        });

    };

noto字体处理。

在入口处(main.dart)里主动下载、加载noto字体。

否则,此文件将从外网CDN匹配和下载;并且加载过程中,界面的文字会展示乱码。

var fontLoader2 = FontLoader("Noto Sans SC"

);

fontLoader2.addFont(fetchFont2());

await

 fontLoader2.load()

Future<ByteData> fetchFont2() async

 {

  var url = Uri

.parse(

    http://{your-cdn-host}/ah-assets/k3kXo84MPvpLmixcA63oeALhL4iJ-Q7m8w%20%281%29.otf

  );

  final response = await http.get

(url);

  if (response.statusCode == 200

) {

    return

 ByteData.view(response.bodyBytes.buffer);

  } else

 {

    throw Exception(Failed to load font

);

  }

}

1.3.2刷新帧率优化

同html的刷新帧率优化。

1.4

首屏优化数据

html模式数据分析对比

抽样测速的数据

同内容的、Vue.js线上版本,抽样测速数据

首次加载, js大文件列表

1.5

分析结果

FFW的html渲染模式,首开速度已经接近传统Vue.js站点;canvaskit模式的刷新帧率效率,也已经接近App端的flutter代码。但是,后者的首屏速度,由于必要的noto字体和wasm内核文件,首开耗时依然过久。

另外,html模式在刷新帧率上有略卡顿的问题。这是由于渲染产物使用了较少的html标签,主要仍依靠canvas绘制;而主流浏览器对于canvas绘制的优化,远没有html标签、DOM树成熟。

Google团队已经将canvaskit渲染模式作为未来优化的方向。为了提升加载速度,在 112 或更高版本的 Chromium中优化了wasm的底层支持,以缩小wasm的体积和提升性能表现。但是短期内现状难以得到有效解决。

所以问题归结为:首开速度和交互性能,不能兼得。

最新的element-embedding技术,为解决此“二选一”难题提供了新的思路。

2. element-embedding新功能

element-embedding是Flutter SDK 3.7的新功能;在2023年的Flutter Forward大会上被推出。在Github的Flutter Sample项目,有两个demo:html+js集成和Angular.js集成。

► 特性:

Flutter的渲染产物,可以作为一个div里的canvas绘制层,而被宿主使用;

这个div可以在任何合适的时机被开启渲染(否则不会加载);

Flutter的代码与它的宿主代码(Angular.js或Vue.js等),可以通过js函数通信。

► 优点:

低侵入性:与传统Vue.js等项目的“混合”,不影响宿主的首屏加载速度等。

可交互性:通过js函数即可完成与宿主的通信。

增加了FFW的使用场景。

3. 替换AB方案

3.1

利用FFW打包2种渲染产物

利用FFW可以方便地打包2种渲染产物的特性:

首屏速度较快,使用html渲染产物。

后续交互性能为了更顺滑,使用canvaskit渲染产物。

3.2

目标是切换过程中用户无感

前者内嵌1个后者的隐藏element-embedding。它会在前者加载完毕后“延迟加载”。

在合适的时机,把前者的“状态参数”传递给后者。

后者更新状态后,“静默替换”展示。

3.3

方案描述

html渲染产物作为“宿主”,首先被加载。

canvaskit渲染产物是一个内部隐藏的element-embedding。

当用户每一次交互“操作”后,都判断一下canvaskit是否渲染完毕。

如果canvaskit已经渲染完毕,则传参、切换、展示。

用户的操作状态得以保持。由于用户的交互状态(滚动位置、切换位置等)通过传参得到保持,切换的过程“近乎无感”。

3.4

应用场景

 页面交互(滚动、点击、切换等)操作不太复杂的场景。

 最后

在纯Web开发领域,传统框架(Vue.js,React.js等)仍是优先的选择。但是,经过技术探索,仍能找到FFW的一些应用场景。尤其App端Flutter代码转为Web/H5的需求很强时,可以考虑使用本文最后讲述的、经过优化和重新架构的FFW方案。

二维码

扫一扫,关注我们

声明:本文由【益华网络】编辑上传发布,转载此文章须经作者同意,并请附上出处【益华网络】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15368564009
在线客服
嘿,我来帮您!