# 【簡単】FlutterでChrome拡張機能を作ってみた

> Flutterを使用してChrome拡張機能を作成する方法について解説。Chrome APIを使用してタブの情報を取得やDartからJavascriptの呼び出しなども解説。

- 公開日: 2025-05-01
- 著者: Matsu
- タグ: Flutter
- URL: https://tech.anycloud.co.jp/articles/flutter-chrome-extention

---

今回は、Flutterで拡張機能を作ってみようと思います！

僕が過去に、チャットワークの一括既読という拡張機能を作ったのですが、具体的な開発方法は載せていなかったので、改めてまとめてみました！

※リリースからしばらく経っているのとGyazoの有料プラン解約して画像も消えてしまいました…今使えるかは分かりません (\*\_ \_)՞՞

<div class="link-card-wrap"><a class="link-card" href="https://zenn.dev/s6lv/articles/ba957da9c1b452" target="_blank" rel="noopener noreferrer"><span class="link-card-body"><span class="link-card-title">【Flutter】チャットワークで一括既読するChrome拡張機能を作りました</span><span class="link-card-meta"><img class="link-card-favicon" src="./linkcard-01-favicon.webp" alt=""><span class="link-card-domain">zenn.dev</span></span></span><img class="link-card-image" src="./linkcard-01-image.webp" alt=""></a></div>

## Flutterプロジェクト作成してローカル起動

Chrome拡張機能なのでプラットフォームはwebでOK！

```shell
% fvm flutter create --platforms web chrome_extension_demo
```

以下コマンドでローカル起動してみます。

```shell
% flutter run -d chrome
```

いつものFlutterの初期カウンターアプリがwebで表示されました。

<figure><img src="./image-001.webp" alt="FLutterカウンターアプリ" width="1362" height="1020"></figure>

## manifest.jsonで拡張機能の基本設定

`web/manifest.json`を以下のように修正します。

```json
{
  "manifest_version": 3,
  "name": "デモ拡張機能",
  "description": "デモ拡張機能です。",
  "version": "1.0.0",
  "content_security_policy": {
    "extension_pages": "script-src 'self' ; object-src 'self'"
  },
  "action": {
    "default_popup": "index.html",
    "default_icon": "/icons/sample.png"
  },
  "icons": {
    "16": "/icons/sample16.png",
    "32": "/icons/sample32.png",
    "48": "/icons/sample48.png",
    "128": "/icons/sample128.png"
  },
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["http://*/*", "https://*/*"],
      "js": ["content_script.js"]
    }
  ],
  "permissions": ["activeTab", "tabs", "scripting", "storage"],
  "host_permissions": ["http://*/*", "https://*/*"]
}
```

基本的な項目だけ簡単に説明します。

<div class="link-card-wrap"><a class="link-card" href="https://developer.chrome.com/docs/extensions/reference/manifest?hl=ja" target="_blank" rel="noopener noreferrer"><span class="link-card-body"><span class="link-card-title">マニフェスト ファイル形式 &nbsp;|&nbsp; Manifest &nbsp;|&nbsp; Chrome for Developers</span><span class="link-card-description">Chrome 拡張機能の manifest.json プロパティの概要。</span><span class="link-card-meta"><img class="link-card-favicon" src="./linkcard-02-favicon.webp" alt=""><span class="link-card-domain">developer.chrome.com</span></span></span></a></div>

-   **name**
    -   Chromeウェブストアでユーザーに表示される拡張機能の名前です。
-   **description**
    -   拡張機能の説明で、Chromeウェブストアにも表示されます。
-   **icons**
    -   Chromeウェブストアなどのアイコンとして使用され、16x16px, 32x32px, 48x48px, 128x128pxのアイコンを用意する必要があります。

## 簡単なChrome拡張機能を実装してみる

今回は、現在表示しているタブのURLを取得して表示するという拡張機能を作ってみます。

完成系のイメージはこちら↓

<figure><img src="./image-002.webp" alt="現在位表示しているタブのURL取得実演" width="1282" height="714"></figure>

### Flutterにjsを読み込む

Flutter上でjsを使用するために以下のパッケージを使用します。

このパッケージを使うことで、dart側からJavascirptの処理を直接呼び出すサポートをしてくれます。

<div class="link-card-wrap"><a class="link-card" href="https://pub.dev/packages/js" target="_blank" rel="noopener noreferrer"><span class="link-card-body"><span class="link-card-title">js | Dart package</span><span class="link-card-description">Annotations to create static Dart interfaces for JavaScript APIs.</span><span class="link-card-meta"><img class="link-card-favicon" src="./linkcard-03-favicon.ico" alt=""><span class="link-card-domain">pub.dev</span></span></span><img class="link-card-image" src="./linkcard-03-image.webp" alt=""></a></div>

```yaml
dependencies:
  flutter:
    sdk: flutter
  js: ^0.6.5
```

### index.htmlの整理

拡張機能を表示するhtmlの基本設定です。

`content_script.js`の読み込みと、拡張機能ポップアップのサイズ（`<html style="height: 500px; width: 450px">`）を指定しておきましょう。

```html
<!DOCTYPE html>
<html style="height: 500px; width: 450px">
<head>
  <base href="$FLUTTER_BASE_HREF">
  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="chrome_extension_demo">
  <link rel="apple-touch-icon" href="icons/sample.png">
  <link rel="icon" type="image/png" href="icons/sample.png" />
  <title>chrome_extension_demo</title>
  <link rel="manifest" href="manifest.json">
</head>
<body>
  <script type="application/javascript" src="main.dart.js"></script>
  <script type="application/javascript" src="content_script.js"></script>
</body>
</html>
```

### Chrome APIを使用してタブの情報を取得

タブのURLを取得するにあたり、`chrome.tabs` API を使用してブラウザのタブシステムを操作します。

[https://developer.chrome.com/docs/extensions/reference/api/tabs?hl=ja#get-the-current-tab](https://developer.chrome.com/docs/extensions/reference/api/tabs?hl=ja#get-the-current-tab)

この API を使用すると、ブラウザのタブを作成、変更、並べ替えなどができます。

`web/content_script.js`

```javascript
async function getUrl() {
  let queryOptions = { active: true, lastFocusedWindow: true };
  let [tab] = await chrome.tabs.query(queryOptions);
  return tab.url;
}
```

### main.dartでアプリUIと機能作成

`lib/main.dart`

```dart
import 'package:flutter/material.dart';
import './content_script.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String currentUrl = 'URL未取得';

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () async {
                var url = await getUrl();
                setState(() {
                  currentUrl = url;
                });
              },
              child: const Text('このページのURLを取得・表示'),
            ),
            const SizedBox(height: 32),
            Text(
              currentUrl,
              style: const TextStyle(fontSize: 16, color: Colors.black),
            ),
          ],
        ),
      ),
    );
  }
}
```

`lib/content_script.dart`

ここでは、jsパッケージを使用してjsの呼び出しをしています。

```dart
@JS()
library chrome_api;

import 'package:js/js.dart';
import 'package:js/js_util.dart';

@JS('getUrl')
external Object _getUrl();

Future<String> getUrl() async {
  return promiseToFuture<String>(_getUrl());
}
```

ここまでできたらあとはビルドするだけです。

ちなみに、`flutter run`で表示の確認はできますが、Chrome APIの実行はローカルでできませんので注意してください。

<figure><img src="./image-003.webp" alt="" width="1392" height="850"></figure>

### ビルドする

拡張機能としてビルドします。

```shell
%  flutter build web --web-renderer html --csp                                                                                                           13:02:15

Compiling lib/main.dart for the Web...
✓ Built build/web
```

## Chrome拡張機能として読み込む

`chrome://extensions/` ページを開きます。

右上の「デベロッパーモード」をオンにしておきましょう。

<figure><img src="./image-004.webp" alt="Chrome拡張機能" width="1499" height="689"></figure>

そして、「パッケージ化されていない拡張機能を読み込む」を選択すると、ファイル選択のポップアップが表示されるので、ソースコードの「buildフォルダ」内にある「webフォルダ」を選択して決定してください。

<figure><img src="./image-005.webp" alt="フォルダ" width="565" height="415"></figure>

以下のように追加されていればOKです。

<figure><img src="./image-006.webp" alt="デモ拡張機能アプリを読み込み" width="817" height="455"></figure>

## 実際に拡張機能を使ってみる

実際に確認してみます。

<figure><img src="./image-007.webp" alt="拡張機能の表示確認" width="1283" height="740"></figure>

ボタンをクリックすると…

<figure><img src="./image-008.webp" alt="現在位表示しているタブのURL取得実演" width="1282" height="714"></figure>

URLが取得できていますね！

## まとめ

いかがでしたか？

Flutterでも意外と簡単に拡張機能を作ることができました！

Flutter信者はぜひ試してみてください！

## 番外編：Chromeウェブストアへリリースもできる

Chromeウェブストアのデベロッパーアカウントを作成（$5の費用がかかります）してリリースすることもできます。

今回はそこまでやりませんが、興味ある方はぜひ。

<div class="link-card-wrap"><a class="link-card" href="https://developer.chrome.com/docs/extensions?hl=ja" target="_blank" rel="noopener noreferrer"><span class="link-card-body"><span class="link-card-title">Chrome 拡張機能 &nbsp;|&nbsp; Chrome Extensions &nbsp;|&nbsp; Chrome for Developers</span><span class="link-card-description">Chrome 拡張機能の開発方法をご確認ください。</span><span class="link-card-meta"><img class="link-card-favicon" src="./linkcard-04-favicon.webp" alt=""><span class="link-card-domain">developer.chrome.com</span></span></span></a></div>
