自定義 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>
  <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""html" String

引擎設定範例

透過 initializeEngine 方法,你可以向 Flutter 應用程式傳遞上述任何設定引數。

請看下面這個例子。

你的 Flutter 應用程式使用 id="flutter_app" 的 HTML 元素,並使用 canvaskit 渲染器。 JavaScript 程式碼就像下面這樣:

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() 以預設設定初始化引擎,然後在初始化完成後立即啟動應用程式。

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

範例:顯示進度指示器

為了在應用程式初始化過程中向用戶提供反饋,請使用各個階段提供的鉤子來更新 DOM:

<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