本页详细介绍了 Flutter Web 应用的初始化过程以及如何对其进行自定义。

启动引导

#

在构建输出目录 (`build/web`) 中,`flutter build web` 命令会生成一个名为 `flutter_bootstrap.js` 的脚本。此文件包含初始化和运行 Flutter 应用所需的 JavaScript 代码。您可以通过在 Flutter 应用的 `web` 子目录中的 `index.html` 文件中为此脚本放置一个异步脚本标签来使用它

html
<html>
  <body>
    <script src="flutter_bootstrap.js" async></script>
  </body>
</html>

或者,您可以通过在 `index.html` 文件中插入模板标记 `{{flutter_bootstrap_js}}` 来内联 `flutter_bootstrap.js` 文件的全部内容。

html
<html>
  <body>
    <script>
      {{flutter_bootstrap_js}}
    </script>
  </body>
</html>

在构建步骤中,当 `index.html` 文件被复制到输出目录 (`build/web`) 时,`{{flutter_bootstrap_js}}` 标记会替换为 `flutter_bootstrap.js` 文件的内容。

自定义初始化

#

默认情况下,`flutter build web` 会生成一个 `flutter_bootstrap.js` 文件,该文件对您的 Flutter 应用进行简单的初始化。然而,在某些情况下,您可能需要自定义此初始化过程,例如:

  • 为您的应用设置自定义 Flutter 配置。
  • 更改 Flutter service worker 的设置。
  • 编写自定义 JavaScript 代码以在启动过程的不同阶段运行。

要编写您自己的自定义引导逻辑而不是使用构建步骤生成的默认脚本,您可以在项目的 `web` 子目录中放置一个 `flutter_bootstrap.js` 文件,该文件将被复制并替代构建生成的默认脚本。此文件也是模板化的,您可以插入几个特殊标记,构建步骤在将 `flutter_bootstrap.js` 文件复制到输出目录时会在构建时进行替换。下表列出了构建步骤将在 `flutter_bootstrap.js` 或 `index.html` 文件中替换的标记:

标记替换为
{{flutter_js}}使 `FlutterLoader` 对象在 `_flutter.loader` 全局变量中可用的 JavaScript 代码。(有关更多详细信息,请参阅下面的 `_flutter.loader.load() API` 部分。)
{{flutter_build_config}}一个 JavaScript 语句,用于设置构建过程生成的元数据,该元数据为 `FlutterLoader` 提供正确引导您的应用所需的信息。
{{flutter_service_worker_version}}一个表示 service worker 构建版本的唯一数字,可以作为 service worker 配置的一部分传递(参见下面的“常见警告”信息)。
{{flutter_bootstrap_js}}如上所述,这会将 `flutter_bootstrap.js` 文件的内容直接内联到 `index.html` 文件中。请注意,此标记只能在 `index.html` 中使用,而不能在 `flutter_bootstrap.js` 文件本身中使用。

编写自定义引导脚本

#

任何自定义的 `flutter_bootstrap.js` 脚本需要包含三个组件才能成功启动您的 Flutter 应用:

  • 一个 `{{flutter_js}}` 标记,使 `_flutter.loader` 可用。
  • 一个 `{{flutter_build_config}}` 标记,它向 `FlutterLoader` 提供启动您的应用所需的构建信息。
  • 调用 `_flutter.loader.load()`,它实际上启动了应用。

最基本的 `flutter_bootstrap.js` 文件可能如下所示:

js
{{flutter_js}}
{{flutter_build_config}}

_flutter.loader.load();

自定义 Flutter 加载器

#

`_flutter.loader.load()` JavaScript API 可以使用可选参数调用以自定义初始化行为:

名称描述JS 类型
config您的应用的 Flutter 配置。对象
onEntrypointLoaded当引擎准备好初始化时调用的函数。接收一个 `engineInitializer` 对象作为其唯一参数。函数

`config` 参数是一个可以包含以下可选字段的对象:

名称描述Dart 类型
assetBase应用 `assets` 目录的基本 URL。当 Flutter 从与实际 Web 应用不同的域或子目录加载时添加此项。当您将 Flutter web 嵌入到另一个应用中,或者将其资产部署到 CDN 时,您可能需要此项。字符串
canvasKitBaseUrl下载 `canvaskit.wasm` 的基本 URL。字符串
canvasKitVariant要下载的 CanvasKit 变体。您的选项包括:

1. `auto`:下载适用于浏览器的最佳变体。此选项为默认值。
2. `full`:下载可在所有浏览器中运行的 CanvasKit 完整变体。
3. `chromium`:下载使用 Chromium 兼容 API 的较小 CanvasKit 变体。**警告**:除非您只打算使用基于 Chromium 的浏览器,否则不要使用 `chromium` 选项。
字符串
canvasKitForceCpuOnly当为 `true` 时,在 CanvasKit 中强制进行仅 CPU 渲染(引擎将不使用 WebGL)。布尔值
canvasKitMaximumSurfacesCanvasKit 渲染器可以使用的最大叠加层表面数。双精度浮点数
debugShowSemanticNodes如果为 `true`,Flutter 会在屏幕上可见地渲染语义树(用于调试)。布尔值
entryPointBaseUrl您的 Flutter 应用入口点的基本 URL。默认为“/”。字符串
hostElementFlutter 渲染应用的 HTML 元素。如果未设置,Flutter Web 将接管整个页面。HtmlElement
renderer指定当前 Flutter 应用的web 渲染器,可以是 "canvaskit""skwasm"字符串

示例:根据 URL 查询参数自定义 Flutter 配置

#

以下示例展示了一个自定义的 `flutter_bootstrap.js`,它允许用户通过在其网站的 URL 中提供 `renderer` 查询参数(例如 `?renderer=skwasm`)来选择渲染器:

js
{{flutter_js}}
{{flutter_build_config}}

const searchParams = new URLSearchParams(window.location.search);
const renderer = searchParams.get('renderer');
const userConfig = renderer ? {'renderer': renderer} : {};
_flutter.loader.load({
  config: userConfig,
});

此脚本评估页面的 `URLSearchParams` 以确定用户是否传递了 `renderer` 查询参数,然后更改 Flutter 应用的用户配置。

onEntrypointLoaded 回调

#

您还可以将 `onEntrypointLoaded` 回调传递给 `load` API,以便在初始化过程的不同部分执行自定义逻辑。初始化过程分为以下几个阶段:

加载入口点脚本
一旦 Service Worker 初始化完成,并且 `main.dart.js` 入口点已被浏览器下载并运行,`load` 函数就会调用 `onEntrypointLoaded` 回调。在开发过程中,Flutter 也会在每次热重启时调用 `onEntrypointLoaded`。
初始化 Flutter 引擎
`onEntrypointLoaded` 回调接收一个 **引擎初始化器** 对象作为其唯一参数。使用引擎初始化器的 `initializeEngine()` 函数来设置运行时配置,例如 `multiViewEnabled: true`,并启动 Flutter web 引擎。
运行应用
`initializeEngine()` 函数返回一个Promise,它会解析为一个 **应用运行器** 对象。应用运行器有一个方法 `runApp()`,用于运行 Flutter 应用。
向应用添加视图(或从应用移除视图)
`runApp()` 方法返回一个 **Flutter 应用** 对象。在多视图模式下,可以使用 `addView` 和 `removeView` 方法从宿主应用管理应用视图。要了解更多信息,请查看嵌入模式

示例:显示进度指示器

#

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

js
{{flutter_js}}
{{flutter_build_config}}

const loading = document.createElement('div');
document.body.appendChild(loading);
loading.textContent = "Loading Entrypoint...";
_flutter.loader.load({
  onEntrypointLoaded: async function(engineInitializer) {
    loading.textContent = "Initializing engine...";
    const appRunner = await engineInitializer.initializeEngine();

    loading.textContent = "Running app...";
    await appRunner.runApp();
  }
});

常见警告

#

如果您遇到类似于以下的警告:

text
Warning: In index.html:37: Local variable for "serviceWorkerVersion" is deprecated.
Use "" template token instead.

您可以通过删除 `web/index.html` 文件中的以下行来解决此问题:

web/index.html
html
var serviceWorkerVersion = null;