自定义 Web 应用程序的初始化

你可以使用 flutter.js 提供的 _flutter.loader JavaScript API 来自定义 Flutter 应用程序在 web 上的初始化方式。该 API 可以用于在 CSS 中显示加载指示器,也可以根据条件阻止加载应用程序,还可以等待用户按下按钮后再显示应用程序。

初始化过程分为以下阶段:

加载入口脚本
获取 main.dart.js 脚本并初始化 service worker。

初始化 Flutter 引擎
通过下载所需资源(如静态资源、字体和 CanvasKit)来初始化 Flutter web 引擎。

运行应用程序
为 Flutter 应用程序准备 DOM 并运行。

本篇介绍了如何自定义初始化过程各个阶段的行为。

入门指南

#

默认情况下,flutter create 指令生成的 index.html 文件包含一个 script 标签,用于调用 flutter.js 文件中的 loadEntrypoint

html
<html>
  <head>
    <!-- ... -->
    <script src="flutter.js" defer></script>
  </head>
  <body>
    <script>
      window.addEventListener('load', function (ev) {
        // Download main.dart.js
        _flutter.loader.loadEntrypoint({
          serviceWorker: {
            serviceWorkerVersion: serviceWorkerVersion,
          },
          onEntrypointLoaded: async function(engineInitializer) {
            // Initialize the Flutter engine
            let appRunner = await engineInitializer.initializeEngine();
            // Run the app
            await appRunner.runApp();
          }
        });
      });
    </script>
  </body>
</html>

一旦 Service Worker 初始化,且浏览器下载并运行了 main.dart.js 入口, loadEntrypoint 函数就会调用 onEntrypointLoaded 回调。 Flutter 还会在开发过程中每次热重载时调用 onEntrypointLoaded

onEntrypointLoaded 回调接收一个 engine initializer 对象作为唯一参数。使用 engine initializer 设置运行时的配置,并启动 Flutter Web 引擎。

initializeEngine() 函数返回一个包含了 app runner 对象的 Promise。 app runner 只有一个 runApp() 方法,它用于运行 Flutter 应用程序。

自定义 web 应用程序的初始化

#

在本节中,了解如何自定义应用程序初始化的各个阶段。

加载入口

#

loadEntrypoint 方法接受以下参数:

参数名称 描述 JS 类型
entrypointUrl Flutter 应用程序入口的 URL。默认为 "main.dart.js" String
onEntrypointLoaded 当引擎准备初始化时调用的函数。该函数的唯一参数是一个 engineInitializer 对象。 Function
serviceWorker flutter_service_worker.js 加载器的配置。(如果未设置,则不会使用 service worker)。 Object

serviceWorker JavaScript 对象接受以下属性:

属性名称 描述 JS 类型
serviceWorkerUrl Service Worker JS 文件的 URL。serviceWorkerVersion 会附加到 URL 中。默认为 "flutter_service_worker.js?v=" String
serviceWorkerVersion 构建过程会赋值 serviceWorkerVersion 变量 并在 index.html 中运用。 String
timeoutMillis service worker 负载的超时时间(毫秒)。默认为 4000 Number

初始化引擎

#

Flutter 3.7.0 版本 起,你可以使用 initializeEngine 方法通过纯 JavaScript 对象配置 Flutter web 引擎的多个运行时选项。

你可以添加以下任何可选参数:

参数名称 描述 Dart 类型
assetBase 应用程序 assets 目录的根 URL。当 Flutter 从实际 web 应用不同的域或子目录加载时,请添加此 URL。当你将 Flutter web 嵌入另一个应用程序,或将其静态资源部署到 CDN 时,可能需要使用此 URL。 String
canvasKitBaseUrl 下载 canvaskit.wasm 的根 URL。 String
canvasKitVariant 下载 CanvasKit。你的可选值:

1. auto:为浏览器下载最佳版本。(默认值)
2. full:下载适用于所有浏览器的 CanvasKit 完整版。
3. chromium:下载较小的 CanvasKit,该版本使用与 Chromium 兼容的 API。警告:除非你只打算使用基于 Chromium 的浏览器,否则不要使用 chromium 值。
String
canvasKitForceCpuOnly true 时,强制在 CanvasKit 中只使用 CPU 进行渲染(引擎不会使用 WebGL)。 bool
canvasKitMaximumSurfaces CanvasKit 渲染器可使用的最大覆盖层数。 double
debugShowSemanticNodes 如果为 true,Flutter 会在屏幕上明显呈现 semantics 语义树(用于调试)。 bool
hostElement 用于 Flutter 渲染应用程序的 HTML 元素。未设置时,Flutter web 会占据整个页面。 HtmlElement
renderer 指定当前 Flutter 应用程序的 web 渲染器,可选 "canvaskit""skwasm" String

引擎配置示例

#

通过 initializeEngine 方法,你可以向 Flutter 应用程序传递上述任何配置参数。

请看下面这个例子。

你的 Flutter 应用程序使用 id="flutter_app" 的 HTML 元素,并使用 canvaskit 渲染器。 JavaScript 代码就像下面这样:

js
onEntrypointLoaded: async function(engineInitializer) {
  let appRunner = await engineInitializer.initializeEngine({
    hostElement: document.querySelector("#flutter_app"),
    renderer: "canvaskit"
  });
  appRunner.runApp();
}

有关每个参数的详细解释,请查阅 web 引擎 configuration.dart 文件中,文档的 "Runtime parameters" 部分。

跳过此步骤

#

与其在 engine initializer 上调用 initializeEngine() (然后在 app runner 上调用 runApp()),不如调用 autoStart() 以默认配置初始化引擎,然后在初始化完成后立即启动应用程序。

js
_flutter.loader.loadEntrypoint({
  serviceWorker: {
    serviceWorkerVersion: serviceWorkerVersion,
  },
  onEntrypointLoaded: async function(engineInitializer) {
    await engineInitializer.autoStart();
  }
});

示例:显示进度指示器

#

为了在应用程序初始化过程中向用户提供反馈,请使用各个阶段提供的钩子来更新 DOM:

html
<html>
  <head>
    <!-- ... -->
    <script src="flutter.js" defer></script>
  </head>
  <body>
    <div id="loading"></div>
    <script>
      window.addEventListener('load', function(ev) {
        var loading = document.querySelector('#loading');
        loading.textContent = "Loading entrypoint...";
        _flutter.loader.loadEntrypoint({
          serviceWorker: {
            serviceWorkerVersion: serviceWorkerVersion,
          },
          onEntrypointLoaded: async function(engineInitializer) {
            loading.textContent = "Initializing engine...";
            let appRunner = await engineInitializer.initializeEngine();

            loading.textContent = "Running app...";
            await appRunner.runApp();
          }
        });
      });
    </script>
  </body>
</html>

更多关于实用的 CSS 动画示例,请查阅 Flutter Gallery 的 初始化代码

升级旧项目

#

如果你的项目是在 Flutter 2.10 或更早版本中创建的,你可以通过运行 flutter create 指令创建一个带有最新初始化模板的 index.html 文件,方法如下。

首先,删除 /web 目录中的文件。

然后,在项目目录下运行以下指令:

flutter create . --platforms=web