你有没有想过为 Dart 和 Flutter 开发一些工具,却苦于不知从何下手?又或者,你不想费劲去搞定如何连接到正在运行的 Dart 或 Flutter 应用,以便获取调试数据?就算工具做出来了,又该怎么部署,怎么让大家方便地用上呢?
现在,有个好消息要告诉你:所有这些难题,都将迎刃而解。
有了全新的 Dart & Flutter DevTools 扩展框架,你就能轻松打造出与现有 DevTools 工具套件紧密结合的开发者工具。这些扩展基于 Flutter Web 构建,并充分利用了 DevTools 现有的框架和实用工具,大大简化了开发者工具的创作过程。

DevTools 扩展是如何运作的?
DevTools 扩展会作为 pub 包的一部分进行发布。你可以选择将 DevTools 扩展添加到现有的 pub 包中,也可以专门创建一个只提供 DevTools 扩展的新包。无论哪种情况,最终用户都必须在其应用中,将提供 DevTools 扩展的那个包列为依赖项,这样才能在 DevTools 中看到这个扩展。
举个例子,假设我们有一个 package:foo 包,并且这个包提供了一个 DevTools 扩展。当用户在他们的应用中依赖 package:foo 时,他们就会自动获得这个包提供的 DevTools 扩展的访问权限。当 DevTools 检测到 package:foo 扩展可用时(根据用户应用或 IDE 提供的信息),DevTools 中就会新增一个名为"Foo"的标签页,里面包含了 package:foo 提供的开发者工具。

一些已经将 DevTools 扩展添加到现有包中的例子有:package:provider、package:patrol 和 package:drift。
支持哪些类型的工具?
借助 DevTools 扩展框架,你可以构建多种类型的工具,包括:
- 现有包的配套工具
- 作为独立包发布的新工具
- 与正在运行的应用交互的工具
- 不与正在运行的应用交互的工具
- 与 IDE 中打开的项目文件交互的工具
- 未来计划: 与分析服务器交互的工具(如果你希望此功能尽快实现,请为这个 issue 点赞!)
DevTools 扩展框架提供了开箱即用的功能,让你的扩展分发给用户变得无缝衔接:
- 用户可以在浏览器中的 DevTools 里使用你的工具
- 用户可以直接在他们的 IDE 中嵌入并使用你的工具
- 用户可以从 Dart 和 Flutter 支持的 IDE 中发现并打开你的工具
现在,让我们开始吧!
编写 DevTools 扩展:分步指南
开始之前
你需要准备:
- Flutter SDK 版本 >=
3.17.0--0.0.pre& Dart SDK 版本 >=3.2。 - 一个
Pub包(可以是现有包,也可以是新创建的),用于添加 DevTools 扩展。
为了使用最新的
devtools_extensions和devtools_app_shared包,你可以在 Flutter 的master或beta通道进行扩展开发。
第一步:设置你的包层级结构
独立扩展
对于独立扩展(即不作为现有 pub 包的一部分发布的扩展),你可以将扩展的源代码包含在发布该扩展的同一个包中。这样做可以简化开发,而且由于你的包的用户会将其作为 dev_dependency(开发依赖)添加,所以你的包大小不会影响用户应用的大小。你的包结构将如下所示:
arduino
my_new_tool
extension/
devtools/
build/
... # lib/ 目录下 Flutter web 应用的预编译输出
config.yaml
lib/ # 你的扩展 Flutter web 应用的源代码
src/
...
由于扩展必须构建为 Flutter web 应用,请使用 flutter create 命令来为你(的 DevTools)扩展生成包:
bash
flutter create --template app --platforms web my_new_tool
现在,在下一步中使用 my_new_tool 包来配置你的扩展。
伴随式扩展
对于伴随式扩展(即作为现有 pub 包的一部分发布的扩展),我们建议你将扩展的源代码放在你的 pub 包之外。这将有助于尽可能减小你的包大小,因为你会希望避免增加依赖你包的用户应用的大小。这里是推荐的包结构:
bash
foo/ # 你pub包的(原)仓库根目录
packages/
foo/ # 你的pub包
extension/
devtools/
build/
... # foo_devtools_extension/lib 的预编译输出
config.yaml
foo_devtools_extension/
lib/ # 你的扩展 Flutter web 应用的源代码
第二步:配置你的扩展
在将为用户提供 DevTools 扩展的 Dart 包中,添加一个顶级的 extension 目录:
swift
foo/
extension/
lib/
...
在 extension 目录下,严格按照所示创建以下结构:
arduino
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 # 可选项 - 默认是 true
复制上面 config.yaml 文件的内容,并粘贴到你刚刚在包中创建的 config.yaml 文件里。务必使用所示的确切文件名和字段名,否则你的扩展可能无法在 DevTools 中加载。
对于每个键,填写你的包的相应值。
name: 此 DevTools 扩展所属的包名。此字段的值将用于扩展页面的标题栏。 [必填]version: 你的 DevTools 扩展的版本号。随着你为扩展发布新功能,此版本号应随时间演进。此字段的值将用于扩展页面的标题栏。 [必填]issueTracker: 你的问题追踪器的 URL。当用户点击 DevTools UI 中的"报告问题"链接时,他们将被定向到此 URL。 [必填]

materialIconCodePoint: 对应于material/icons.dart中某个图标的 codepoint 值。此图标将用于 DevTools 顶级标签栏中该扩展的标签页。 [必填]

requiresConnection: 表示该扩展是否需要连接到一个 Dart 或 Flutter 应用才能使用。这是一个可选字段,如果未指定,将默认为true。 [可选]
有关 config.yaml 规范的最新文档,请参阅 extension_config_spec.md。
现在是时候构建你的扩展了。
第三步:构建你的扩展
创建 Flutter web 应用。
注意: 如果你正在构建一个独立扩展,请跳过此步骤,因为你已经在设置包层级结构时完成了此操作。
- 在你希望扩展源代码所在的目录中,运行以下命令,将
foo_devtools_extension替换为<你的包名>_devtools_extension:
css
flutter create --template app --platforms web foo_devtools_extension
- 将
package:devtools_extensions依赖项添加到你的扩展 Flutter web 应用中。
csharp
flutter pub add devtools_extensions
你可能还会希望添加对 package:devtools_app_shared 的依赖,该包包含共享服务、实用工具和 UI 组件,供你在构建扩展时使用。请参阅 devtools_app_shared/example 获取示例用法。
csharp
flutter pub add devtools_app_shared
在你的 Flutter web 应用的根部添加 DevToolsExtension Widget。 在 lib/main.dart 中,添加以下内容:
dart
import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const DevToolsExtension());
}
class FooDevToolsExtension extends StatelessWidget {
const FooDevToolsExtension({super.key});
@override
Widget build(BuildContext context) {
return const DevToolsExtension(
child: Placeholder(), // Build your extension here
);
}
}
DevToolsExtension Widget 会自动执行与 DevTools 交互所需的所有扩展初始化。在你的扩展 web 应用的任何地方,你都可以访问以下全局变量:
extensionManager: 一个用于与 DevTools 或扩展框架交互的管理器。serviceManager: 一个用于与已连接的 VM 服务交互的管理器(如果存在)。dtdManager: 一个用于与 Dart Tooling Daemon 交互的管理器(如果存在)。
第四步:调试你的扩展
在开发和维护你的 DevTools 扩展时,你会希望运行、调试和测试你的扩展 Flutter web 应用。你有几种不同的选项,如下所述。
选项 A:使用模拟的 DevTools 环境(推荐用于开发)
出于调试目的,你可能希望使用"模拟的 DevTools 环境"。这是一个模拟环境,允许你构建扩展,而无需将其开发为 DevTools 中的嵌入式 iFrame。以这种方式运行你的扩展,会用一个模拟 DevTools 到 DevTools 扩展连接的环境来包裹你的扩展。它还为你提供了热重启和更快的开发周期。

- 你的 DevTools 扩展。
- 测试应用的 VM 服务 URI,你的 DevTools 扩展将与该应用进行交互。这个应用应该依赖于你的扩展的父包(本例中是
package:foo)。 - 用于执行用户可能从 DevTools 触发的操作的按钮。
- 显示你的扩展和 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"
],
},
]
}
或者从命令行启动你的应用,并添加以下标志:
ini
flutter run -d chrome - dart-define=use_simulated_environment=true
选项 B:使用真实的 DevTools 环境
一旦你的扩展开发到一定阶段,准备好在真实的 DevTools 环境中测试你的更改时,你需要执行一系列设置步骤:
- 将你的扩展开发到可以准备在真实的 DevTools 环境中测试更改的程度 。构建你的 Flutter web 应用,并将构建好的资源从
your_extension_web_app/build/web复制到你的pub包的extension/devtools/build目录。 使用package:devtools_extensions中的build_and_copy命令来帮助完成此步骤。
bash
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 包添加扩展,那么 --dest 的值应该是 ../你的_pub_包/extension/devtools。
为了确保你的扩展在 DevTools 中加载设置正确,请运行 package:devtools_extensions 中的 validate 命令。--package 参数应该指向将发布此扩展的 Dart 包的根目录。
bash
cd your_extension_web_app;
flutter pub get;
dart run devtools_extensions validate --package=path/to/your_pub_package
-
准备一个测试环境,并添加对提供扩展的
pub包的依赖。 在你添加对你的包的依赖的 Dart 或 Flutter 项目中,添加一个指向你本地包源代码的path依赖(该包包含你的扩展资源的extension/devtools/目录)。完成此操作后,在该包上运行pub get。 如果你的扩展需要一个正在运行的应用程序,那么你需要运行依赖于你的扩展的应用程序。 如果你的扩展不需要正在运行的应用程序,那么你需要在支持的 IDE(VS Code 或 IntelliJ / Android Studio)中打开依赖于你的包的测试 Dart 或 Flutter 项目。 -
通过以下方式之一启动 DevTools: 如果你的扩展需要一个正在运行的应用程序,你可以从运行测试应用程序时命令行打印的 URI 中打开 DevTools,或者从你运行测试应用程序的 IDE 中打开 DevTools。 如果你的扩展不需要正在运行的应用程序,你可以在支持的 IDE(VS Code 或 IntelliJ / Android Studio)中打开依赖于你的包的 Dart 或 Flutter 项目。从 IDE 中打开 DevTools,以在浏览器中查看你的扩展。 如果你需要 DevTools 的本地或未发布更改,你需要从源代码构建并运行 DevTools。请参阅 DevTools 的
CONTRIBUTING.md以获取操作指南。你需要构建带有服务器和前端的 DevTools 来测试扩展------请参阅 说明。 -
**打开 DevTools 后,你会在 DevTools 应用栏中看到你的扩展的标签页。**你的扩展的启用或禁用状态由 DevTools 管理,并通过屏幕右上角操作按钮中的"扩展"菜单进行公开。


第五步:发布你的包含 DevTools 扩展的包
为了让一个包能向其用户提供 DevTools 扩展,它必须在发布时包含 your_pub_package/extension/devtools/ 目录下预期的内容(请参阅上面的设置说明)。
- 确保
extension/devtools/config.yaml文件存在,并已按照上述规范进行配置。你可以运行package:devtools_extensions中的validate命令进行验证。
bash
cd your_extension_web_app;
flutter pub get;
dart run devtools_extensions validate --package=path/to/pkg_providing_your_extension_assets
- 使用
package:devtools_extensions提供的build_and_copy命令来构建你的扩展,并将输出复制到extension/devtools目录:
ini
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 扩展中提供的工具。
对于问题和功能请求,请在 DevTools 的 问题追踪器 上提交问题。
如需一般支持和访问 DevTools 扩展作者社区,请查看 Discord 频道 #devtools-extension-authors(你需要首先加入 Flutter Discord 服务器)。
最后欢迎关注我的公众号:OpenFlutter,感恩。