[Flutter] Devtools Extensions で独自の Devtool を開発する

2024/12/07に公開

👀 はじめに

この記事は FlutterKaigi 2024 での登壇内容を要約したもです。
合わせてこちらの動画やスライドも参照ください。
https://www.youtube.com/live/CE0NTGJLbS8?si=i_06Ifsg3mBXQvuT&t=25301
https://github.com/lllttt06/flutter_devtools_extension_sample

🚀 DevTools extensions とは?

Devtool に独自の機能を作成し拡張できる仕組みのこと。作成するとこの画像の flutterkaigi のタブのように新しいタブが自動で生成され、Devtool に統合されます。

Devtools Extensions には以下のような利点があり、Flutter エンジニアにとって開発生産性を向上させる便利なツールとなります。

  • Flutter Web で作成できる
  • 既存 package への統合に加え、独立した package として公開可能
  • 既存の Devtools の仕組みを再利用できる

🐬 DevTools extensions の活用事例

弊チームでは以下のような機能を Devtools extensions で作成しています。
これらの機能のサンプルリポジトリを作成したので、合わせてチェックしてみて下さい。
https://github.com/lllttt06/flutter_devtools_extension_sample

GraphQL Cache Inspector

通信に GraphQL を使用しており、クライアントには graphql_flutter を利用しています。このパッケージにはクライアントキャッシュを確認する機構がないため、Apollo Client を参考に Devtools extensions でキャッシュを確認できる機能を作成しました。

Loading State Toggle

ローディング状態の UI を手軽に確認するための機構です。通常だと一瞬で完了してしまうローディング中の UI を自由に切り替えることができます。この機能も React の Suspense を参考に作成しています。

Dio Logger Toggle

Http クライアントに Dio を用いており、普段の開発ではその通信ログをデバッグコンソールに出力しています。時折すべての Http 通信ログが出力されると見にくくなることがあるため、そのような場合にログ出力を止めるための機能です。

🤖 DevTools extensions の作成方法

Devtools extensions の作成方法は非常にシンプルです。

  1. config.yaml の作成
  2. Devtools extensions のパッケージを Flutter web で作成
  3. Flutter web で build

詳しくはこちらを参照してください。
https://pub.dev/packages/devtools_extensions#create-a-devtools-extension

1. config.yaml の作成

Devtools extensions の設定を記述する config.yaml を作成します。

#config.yaml
name: flutterkaigi
issueTracker: 'https://github.com/lllttt06/flutter_devtools_extension_sample/issues'
version: 0.0.1
materialIconCodePoint: '0xe0b1'
requiresConnection: true
flutter_kaigi/
└── packages/
    └── app/
        ├── extension/
        │   └── devtools/
        │       ├── build/
        │       └── config.yaml
        └── lib/

2. Devtools extensions のパッケージを作成

このサンプルでは devtools_ext という名前のパッケージを作成しています。ここの名前は自由に決めることができます。また devtools_extensions パッケージを必ず追加してください。

$ flutter create --template app --platforms web devtools_ext
$ flutter pub add devtools_extensions
flutter_kaigi/
└── packages/
    ├── app/
    │   ├── extension/
    │   │   └── devtools/
    │   │       ├── build/
    │   │       └── config.yaml
    │   └── lib/
    └── devtools_ext/
        └── lib/

以下のように devtools_ext の Root 部分で DevToolsExtension という StatefulWidget を使用する必要があります。

https://github.com/lllttt06/flutter_devtools_extension_sample/blob/8bca92f9373d6721fc492e0151f78a99b8bd7673/packages/devtools_ext/lib/main.dart#L7-L61

この StatefulWidget は initState 時に Devtools extension 内で使用可能なグローバル変数の初期化、IDE のテーマ設定、build メソッドでは MaterialApp と Scaffold を内包しています。

https://github.com/flutter/devtools/blob/c5c0673adf7bb7706e5de091bee5aa3f1fc3a699/packages/devtools_extensions/lib/src/template/devtools_extension.dart#L144-L208

Devtools extension 内で使用可能なグローバル変数は ExtensionManager, ServiceManager, DTDManager の 3 つが用意されています。それぞれ以下のような役割を担っており、Devtools extension の開発をサポートします。

devtools_ext/lib/main.dart に Widget を追記後、以下のコマンドで extension をデバッグしながら開発できます。

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

Devtools extension が実行中のアプリと連携が必要な場合には、以下の画像の Dart VM Service Connection に実行中の VM の URI を入力する必要があります。これはデバッグコンソール上に Connecting to VM Service at という形で出力されるので、その値をコピーして貼りつけます。


Devtools extension と実行中のアプリを連携し、データのやり取りをするには registerExtension メソッドを使用します。実行中のアプリ側(サンプルリポジトリでは app)で registerExtension で Devtools extension から呼び出された際の handler を登録します。また hot reload などで同じ key で何度も handler が登録されることを防ぐために useEffect で初期化時にだけ実行されるようにしています。

https://github.com/lllttt06/flutter_devtools_extension_sample/blob/8bca92f9373d6721fc492e0151f78a99b8bd7673/packages/app/lib/component/devtools_ext_container.dart#L33-L101

Devtools extension 側(サンプルリポジトリでは devtools_ext) では前述した serviceManagercallServiceExtensionOnMainIsolate メソッドで先程登録した handler を呼び出します。

https://github.com/lllttt06/flutter_devtools_extension_sample/blob/8bca92f9373d6721fc492e0151f78a99b8bd7673/packages/devtools_ext/lib/api/app_connection.dart#L4-L37

3. Flutter web で build

Devtools に作成した extension を取り込むには、Flutter web で build する必要があります。作成した devtools_ext 配下で以下のコマンドを実行し、ステップ 1 の config ファイルと同様の path (pacakges/app/extension/devtools) に build 成果物をコピーします。

dart run devtools_extensions build_and_copy --source=. --dest=../app/extension/devtools

📝 まとめ

DevTools Extensions は、Flutter の開発ツールで独自の機能を作成・拡張できる強力な仕組みです。これにより、開発中のアプリに特化したデバッグ機能を追加することが可能になり、開発効率を大幅に向上させます。

DevTools Extensions の作成は、簡単な設定ファイル(config.yaml)の作成から始まり、Flutter Web でパッケージを作成し、ビルドすることで実現できます。デバッグ中に実行中のアプリと連携させることで、より強力なツールとして活用できます。

これにより、Flutter の開発環境がさらに充実し、プロジェクトに合わせたカスタマイズが可能となります。興味がある方は、サンプルリポジトリを参考にして実際に試してみてください。

また Web 界隈の技術を参考にすることで、Flutter の開発者体験を向上させる良いアイデアが湧きやすいです。

Discussion