跳到主內容

在 Flutter 和 Dart DevTools 中構建自定義工具

你是否曾想為 Dart 和 Flutter 構建開發者工具,卻不知道從何入手?或者,你是否不想為了獲取除錯資料而投入大量精力去建立與執行中的 Dart 或 Flutter 應用的連線?即使你建立了一個開發工具,又該如何部署它或讓使用者輕鬆訪問它呢?其實,你可以無需克服這些障礙來建立開發者工具。

藉助 Dart 和 Flutter DevTools 擴充套件框架,你可以輕鬆構建與現有 DevTools 工具套件緊密整合的開發者工具。擴充套件使用 Flutter Web 構建,並利用 DevTools 現有的框架和實用程式,從而簡化了開發者工具的創作體驗。

Example DevTools extension for package:foo

DevTools 擴充套件是如何工作的?

#

擴充套件作為 pub 包的一部分發布。你可以向現有的 pub 包新增 DevTools 擴充套件,也可以建立一個僅提供 DevTools 擴充套件的新包。在這兩種情況下,終端使用者必須在依賴列表中包含提供該 DevTools 擴充套件的包,才能在 DevTools 中看到該擴充套件。

例如,假設我們有一個 package:foo,它提供了一個 DevTools 擴充套件。當用戶在他們的應用中依賴 package:foo 時,他們會自動獲得該包提供的 DevTools 擴充套件的使用許可權。當 DevTools 根據使用者應用或 IDE 中的資訊檢測到 package:foo 擴充套件可用時,會在 DevTools 中新增一個名為“Foo”的新標籤頁,其中包含 package:foo 提供的開發者工具。

Diagram showing how a DevTools extension works

已向現有包新增 DevTools 擴充套件的包示例包括 package:shared_preferencespackage:providerpackage:patrolpackage:drift

支援哪些型別的工具?

#

藉助 DevTools 擴充套件框架,你可以構建多種型別的工具,包括:

  • 現有包的配套工具。
  • 作為獨立包釋出的新工具。
  • 與執行中的應用程式互動的工具。
  • 與 IDE 中開啟的專案檔案互動的工具。
  • 與分析伺服器(Analysis server)互動的工具。

DevTools 擴充套件框架自帶開箱即用的功能,使向用戶分發擴充套件變得無縫。例如,使用者可以:

  • 在瀏覽器中的 DevTools 中使用你的工具。
  • 直接在 IDE 中嵌入使用你的工具。
  • 從支援 Dart 和 Flutter 的 IDE 中發現並開啟你的工具。

接下來,學習如何編寫 DevTools 擴充套件。


編寫 DevTools 擴充套件

#

開始之前,你需要:

  • Flutter SDK >= 3.17 和 Dart SDK >= 3.2。
  • 一個你認為需要自定義 DevTools 擴充套件的 pub 包。

設定你的包層次結構

#

你將提供獨立擴充套件或配套擴充套件。

獨立擴充套件

#

對於獨立擴充套件(非作為現有 pub 包的一部分發布),你的擴充套件可以將原始碼包含在與擴充套件一同釋出的同一個包中。這簡化了開發過程,而且由於你的包使用者會將你的包新增為 dev_dependency,因此包的大小不會影響使用者的應用大小。你的包結構如下所示:

yaml
my_new_tool
  extension/
    devtools/
      build/
        ...  # pre-compiled output of the Flutter web app under lib/
      config.yaml
  lib/  # source code for your extension Flutter web app
    src/
      ...

由於擴充套件是作為 Flutter Web 應用構建的,請使用 flutter create 生成該包:

flutter create --template app --platforms web my_new_tool

接下來,在下一步中使用 my_new_tool 包來配置你的擴充套件。

配套擴充套件

#

對於配套擴充套件(作為現有 pub 包的一部分發布),建議將你的擴充套件原始碼放在 pub 包之外。這可以儘可能減小包的大小,避免增加依賴你包的使用者的應用體積。以下是推薦的包結構:

yaml
foo/  # formerly the repository root of your pub package
  packages/
    foo/  # your pub package
      extension/
        devtools/
          build/
            ...  # pre-compiled output of foo_devtools_extension/lib
          config.yaml
    foo_devtools_extension/
      lib/  # source code for your extension Flutter web app

配置你的擴充套件

#

在向用戶提供 DevTools 擴充套件的 Dart 包中,新增一個頂級 extension 目錄:

yaml
foo/
  extension/
  lib/
  ...

extension 目錄下,建立完全如下所示的結構:

yaml
extension/
  devtools/
    build/
    config.yaml

config.yaml 檔案包含 DevTools 載入擴充套件所需的元資料。

yaml
name: foo
version: 0.0.1
issueTracker: <link_to_your_issue_tracker.com>
materialIconCodePoint: '0xe0b1'
requiresConnection: true  # optional field - defaults to true

按所示內容複製 config.yaml 檔案,並貼上到你剛剛在包中建立的 config.yaml 檔案中。必須嚴格使用所示的檔名和欄位名,否則你的擴充套件可能無法在 DevTools 中載入

對於每個鍵,請填寫適用於你包的相應值。

  • name:此 DevTools 擴充套件的包名稱。該欄位的值用於擴充套件頁面標題欄。[必需]
  • version:你的 DevTools 擴充套件版本。當你為擴充套件釋出新功能時,此版本號應隨之更新。該欄位的值用於擴充套件頁面標題欄。[必需]
  • issueTracker:你的問題追蹤器 URL。當用戶點選 DevTools UI 中的 Report an issue 連結時,他們將被引導至此 URL。[必需]

DevTools extension screen title bar

  • materialIconCodePoint:對應 material/icons.dart 中圖示的碼點值。此圖示用於頂部 DevTools 標籤欄中擴充套件的標籤頁。[必需]

DevTools extension tab icon

  • requiresConnection:指示擴充套件是否需要連線的 Dart 或 Flutter 應用才能使用。這是一個可選欄位,如果不指定,預設為 true。[可選]

有關 config.yaml 規範的最新文件,請訪問 extension_config_spec.md

構建你的擴充套件

#

請按照以下步驟構建擴充套件。

建立 Flutter Web 應用

#

在你想放置擴充套件原始碼的目錄下,執行以下命令,將 foo_devtools_extension 替換為 <your_package_name>_devtools_extension

flutter create --template app --platforms web foo_devtools_extension

新增 package:devtools_extensions 依賴

#
flutter pub add devtools_extensions

你可能還需要新增對 package:devtools_app_shared 的依賴,其中包含構建擴充套件時可使用的共享服務、實用程式和 UI 元件。請訪問 devtools_app_shared/example 檢視示例用法。

flutter pub add devtools_app_shared

新增 DevToolsExtension 元件

#

lib/main.dart 中,新增以下匯入:

dart
import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const FooDevToolsExtension());
}

class FooDevToolsExtension extends StatelessWidget {
  const FooDevToolsExtension({super.key});

  @override
  Widget build(BuildContext context) {
    return const DevToolsExtension(
      child: Placeholder(), // Build your extension here
    );
  }
}

DevToolsExtension 元件會自動初始化與 DevTools 互動所需的所有擴充套件。在你的擴充套件 Web 應用中的任何位置,你都可以訪問以下全域性變數:

  • extensionManager:用於與 DevTools 或擴充套件框架互動的管理器。
  • serviceManager:用於與已連線的 VM 服務(如果存在)互動的管理器。
  • dtdManager:用於與 Dart 工具守護程序(Dart Tooling Daemon,如果存在)互動的管理器。

除錯你的擴充套件

#

在開發和維護 DevTools 擴充套件時,你需要執行、除錯和測試你的擴充套件 Flutter Web 應用。你有幾種不同的選項,如下所述:

#

出於除錯目的,你可能需要使用“模擬 DevTools 環境”。這是一個模擬環境,允許你在無需將其作為嵌入式 iFrame 開發的情況下構建擴充套件。以這種方式執行擴充套件會將你的擴充套件包裹在一個模擬 DevTools 與 DevTools 擴充套件連線的環境中。它還使你可以訪問熱重啟(hot restart)並獲得更快的開發週期。

Debugging an extension with the Simulated DevTools Environment

  1. 你的 DevTools 擴充套件。
  2. 你的 DevTools 擴充套件將與之互動的測試應用的 VM 服務 URI。該應用應依賴於你擴充套件的父包(本例中為 package:foo)。
  3. 用於執行使用者可能從 DevTools 觸發的操作的按鈕。
  4. 顯示將在你的擴充套件和 DevTools 之間傳送的訊息的日誌。

模擬環境由環境變數 use_simulated_environment 啟用。要在此標誌開啟的情況下執行你的擴充套件 Web 應用,請在 VS Code 的 launch.json 檔案中新增一個配置:

json
{
    ...
    "configurations": [
        ...
        {
            "name": "foo_devtools_extension + simulated environment",
            "cwd": "packages/foo_devtools_extension",
            "request": "launch",
            "type": "dart",
            "args": [
                "--dart-define=use_simulated_environment=true"
            ],
        },
    ]
}

或者在命令列中透過新增該標誌來啟動你的應用:

flutter run -d chrome -dart-define=use_simulated_environment=true

選項 B:使用真實的 DevTools 環境

#

一旦你將擴充套件開發到準備在真實的 DevTools 環境中測試更改的程度,你需要執行一系列設定步驟:

  1. 將擴充套件開發到準備在真實 DevTools 環境中測試更改的程度。構建你的 Flutter Web 應用,並將構建的資源從 `your_extension_web_app/build/web` 複製到你的 pub 包的 `extension/devtools/build` 目錄中。

    使用 package:devtools_extensions 提供的 build_and_copy 命令來幫助完成此步驟。

    console cd your_extension_web_app; flutter pub get; dart run devtools_extensions build_and_copy --source=. --dest=path/to/your_pub_package/extension/devtools

    為了確保你的擴充套件已正確設定為可在 DevTools 中載入,請執行 package:devtools_extensions 中的 validate 命令。--package 引數應指向該擴充套件將隨之釋出的 Dart 包的根目錄。

    console cd your_extension_web_app; flutter pub get; dart run devtools_extensions validate --package=path/to/your_pub_package

  2. 準備一個測試環境,該環境依賴於提供擴充套件的 pub 包。

    在添加了對你包的依賴的 Dart 或 Flutter 專案中,新增一個指向你本地包原始碼(包含 extension/devtools/ 目錄及其資源的包)的 path 依賴。完成此操作後,在該包上執行 pub get

    * 如果你的擴充套件需要執行中的應用程式,那麼你需要執行依賴於你的擴充套件的應用程式。 * 如果你的擴充套件不需要執行中的應用程式,那麼你需要在支援的 IDE(VS Code 或 IntelliJ / Android Studio)中開啟依賴於你的包的測試 Dart 或 Flutter 專案。

  3. 啟動 DevTools

    使用以下任一方式啟動 DevTools:

    * 如果你的擴充套件需要執行中的應用程式,你可以透過執行測試應用時列印到命令列的 URI,或者從執行測試應用的 IDE 中開啟 DevTools。 * 如果你的擴充套件不需要執行中的應用程式,你可以在支援的 IDE(VS Code 或 IntelliJ / Android Studio)中開啟依賴於你的包的 Dart 或 Flutter 專案。從 IDE 開啟 DevTools 以在瀏覽器中檢視你的擴充套件。 * 如果你需要來自 DevTools 的本地或未釋出的更改,則需要從原始碼構建並執行 DevTools。有關操作指南,請參閱 DevTools CONTRIBUTING.md。你需要構建帶有伺服器和前端的 DevTools 才能測試擴充套件(說明)。

  4. 如果你的測試應用尚未連線到 DevTools,請將其連線,你應該會在 DevTools 應用欄中看到你的擴充套件標籤頁。擴充套件的啟用或停用狀態由 DevTools 管理,可透過螢幕右上角操作按鈕中的 **Extensions** 選單進行設定。

開啟 DevTools 後,DevTools 應用欄中應該會出現一個擴充套件標籤頁。擴充套件的啟用或停用狀態由 DevTools 管理,可透過螢幕右上角操作按鈕中提供的“Extensions”選單進行訪問。

DevTools Extensions menu button

DevTools Extensions menu

釋出帶有 DevTools 擴充套件的包

#

為了讓包向用戶提供 DevTools 擴充套件,必須在釋出時在 your_pub_package/extension/devtools/ 目錄中包含預期的內容(如前面的設定說明中所述)。

  1. 確保 extension/devtools/config.yaml 檔案存在並已根據上述規範進行配置。你可以執行 package:devtools_extensions 中的 validate 命令進行驗證。
    cd your_extension_web_app;
    flutter pub get;
    dart run devtools_extensions validate --package=path/to/pkg_providing_your_extension_assets
    
  2. 使用 package:devtools_extensions 提供的 build_and_copy 命令構建你的擴充套件,並將輸出複製到 extension/devtools 目錄。

    console cd your_extension_web_app; flutter pub get; dart run devtools_extensions build_and_copy --source=. --dest=path/to/your_pub_package/extension/devtools

然後,在 pub.dev 上釋出你的包。

flutter pub publish

執行 pub publish 時,如果缺少 config.yaml 檔案或 build 目錄為空(這是必需的),你將看到警告。

有關釋出包的其他指導,請訪問 package:devtools_extensions釋出指南


就是這樣!現在,當用戶依賴你的包的最新版本時,他們將自動獲得你透過 DevTools 擴充套件提供的工具的使用許可權。

你可能會覺得以下連結很有用: