Flutter Web 应用初始化
自定义 Flutter 应用在 Web 上的初始化方式。
本页面详细介绍了 Flutter Web 应用的初始化过程以及如何对其进行自定义。
引导程序(Bootstrapping)
#flutter build web 命令会在构建输出目录(build/web)中生成一个名为 flutter_bootstrap.js 的脚本。该文件包含初始化和运行 Flutter 应用所需的 JavaScript 代码。你可以通过在 Flutter 应用 web 子目录下的 index.html 文件中添加一个异步脚本标签来使用此脚本。
<html>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>
或者,你也可以通过在 index.html 文件中插入模板标记 {{flutter_bootstrap_js}},将 flutter_bootstrap.js 文件的全部内容内联到其中。
<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 文件如下所示:
{{flutter_js}}
{{flutter_build_config}}
_flutter.loader.load();
自定义 Flutter 加载器
#_flutter.loader.load() JavaScript API 可以接收可选参数以自定义初始化行为:
| 名称 | 描述 | JS 类型 |
|---|---|---|
config |
应用的 Flutter 配置。 | Object |
onEntrypointLoaded |
当引擎准备好初始化时调用的函数。接收一个 engineInitializer 对象作为其唯一参数。 |
Function |
config 参数是一个对象,可以包含以下可选字段:
| 名称 | 描述 | Dart 类型 |
|---|---|---|
assetBase |
应用 assets 目录的基础 URL。当 Flutter 从与实际 Web 应用不同的域名或子目录加载时,请添加此项。在将 Flutter Web 嵌入其他应用,或将资源部署到 CDN 时,你可能需要此项。 |
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 渲染器可以使用的最大覆盖图层(overlay surfaces)数量。 | double |
debugShowSemanticNodes |
若为 true,Flutter 会在屏幕上直观地渲染语义树(用于调试)。 |
bool |
entrypointBaseUrl |
Flutter 应用入口点的基础 URL。默认为 "/"。 | String |
hostElement |
Flutter 渲染应用的 HTML 元素。如果不设置,Flutter Web 将接管整个页面。 | HtmlElement |
renderer |
为当前的 Flutter 应用指定 Web 渲染器,可选 "canvaskit" 或 "skwasm"。 |
String |
forceSingleThreadedSkwasm |
强制 Skia WASM 渲染器以单线程模式运行以保持兼容性。 | bool |
forceSingleThreadedSkwasm
#一个布尔标志,用于强制 Skia WebAssembly (skwasm) 渲染器在单线程模式下运行。在以下情况中很有用:
- 你的环境不支持多线程 WASM。例如,
SharedArrayBuffer不可用或缺少必要的安全头信息。 - 你想要获得最大的浏览器兼容性。
- 如果支持多线程,请使用
false(默认值)以启用多线程渲染,这可以提高性能。
使用示例
#_flutter.loader.load({
config: {
renderer: 'skwasm',
forceSingleThreadedSkwasm: true,
},
});
示例:根据 URL 查询参数自定义 Flutter 配置
#以下示例展示了一个自定义的 flutter_bootstrap.js,它允许用户通过在网站 URL 中提供 renderer 查询参数(如 ?renderer=skwasm)来选择渲染器:
{{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回调。在开发过程中的每次热重启(hot restart),Flutter 也会调用onEntrypointLoaded。 - 初始化 Flutter 引擎
-
onEntrypointLoaded回调接收一个引擎初始化器对象作为其唯一参数。使用引擎初始化器的initializeEngine()函数来设置运行时配置(例如multiViewEnabled: true),并启动 Flutter Web 引擎。 - 运行应用
-
initializeEngine()函数返回一个Promise,解析后得到一个应用运行器对象。应用运行器有一个单一方法runApp(),用于运行 Flutter 应用。 - 向应用添加(或移除)视图
-
runApp()方法返回一个应用对象。在多视图模式下,可以使用addView和removeView方法从宿主应用管理应用视图。要了解更多信息,请查看嵌入模式。
示例:显示进度指示器
#要在初始化过程中向应用用户提供反馈,请使用每个阶段提供的钩子(hook)来更新 DOM。
{{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();
}
});
常见警告
#如果你遇到类似以下的警告:
Warning: In index.html:37: Local variable for "serviceWorkerVersion" is deprecated.
Use "" template token instead.
你可以通过从 web/index.html 文件中删除以下行来解决此问题:
var serviceWorkerVersion = null;