Chrome の拡張機能を Manifest V3 に対応する

はじめに

Chromeの拡張機能を作成する」で作成した Manifest V2 用の拡張機能を Manifest V3 用に変更します。

開発から既に数年経過しているため、最終的なコードからはかけ離れていますが、 Manifest V3 用のサンプルとしての位置付けでこの記事は作成されています。

※CopyTabTitleUrl の最新コードは、次のサイトで確認できます。
 (最新コードはまだ Manifest V3 には対応していません)
 k08045kk/CopyTabTitleUrl - GitHub

コード

manifest.js{
  "manifest_version": 3,
  "name": "CopyTabTitleUrl",
  "description": "コンテキストメニューを追加して、クリップボードへタイトルとURLをコピーします。",
  "version": "3.0.1",

  "background": {
    "service_worker": "background.js"
  },

  "permissions": [
    "activeTab",
    "contextMenus",
    "clipboardWrite",
    "scripting",
    "tabs"
  ]
}

background.jsconst copyToClipboard = (tab, text) => {
  function injectedFunction(text) {
    try {
      navigator.clipboard.writeText(text);
      //console.log('successfully');
    } catch (e) {
      //console.log('failed');
    }
  }
  chrome.scripting.executeScript({
    target: {tabId: tab.id},
    func: injectedFunction,
    args: [text]
  });
};

const updateContextMenus = async () => {
  await chrome.contextMenus.removeAll();

  chrome.contextMenus.create({
      id: "context-copytab-title-url",
      title: "タブのタイトルとURLをコピー",
      contexts: ["all"]
  });
  chrome.contextMenus.create({
      id: "context-copytab-title",
      title: "タブのタイトルをコピー",
      contexts: ["all"]
  });
  chrome.contextMenus.create({
      id: "context-copytab-url",
      title: "タブのURLをコピー",
      contexts: ["all"]
  });
};

chrome.runtime.onInstalled.addListener(updateContextMenus);
chrome.runtime.onStartup.addListener(updateContextMenus);
chrome.contextMenus.onClicked.addListener((info, tab) => {
  switch (info.menuItemId) {
  case 'context-copytab-title-url':
    copyToClipboard(tab, tab.title+'\n'+tab.url);
    break;
  case 'context-copytab-title':
    copyToClipboard(tab, tab.title);
    break;
  case 'context-copytab-url':
    copyToClipboard(tab, tab.url);
    break;
  }
});

コードの補足

chrome.runtime.onInstalled / chrome.runtime.onStartup

元々、コンテキストメニューの登録処理は、バックグラウンドページに直接記入していました。ですが、バックグラウンドが ServiceWorker となった関係でバックグラウンドの存続期間に大きな変更がありました。

バックグラウンドの存続期間は、 Manifest V2 であればブラウザが開いてから閉じるまでです。ですが、 Manifest V3 では数分程度処理がない場合、バックグラウンドの処理は停止してしまいます。再開する場合、バックグラウンド処理を再度実施します。

Manifest V3 でもコンテキストメニューの登録処理を直接記述することはできます。ですが、バックグラウンド処理の実行毎に実行されるのはあまり気持ちが良いものではありません。そのため、chrome.runtime.onInstalled / chrome.runtime.onStartupで特定のタイミング(インストール時・更新時・起動時)に実行しています。

chrome.scripting.executeScript

ServiceWorker には、documentがありません。そのため、古いクリップボードコピーの方式(document.execCommand("copy"))が利用できません。

新しいクリップボードコピーの方式(navigator.clipboard.writeText())も ServiceWorker 上からはアクセスできません。

拡張機能の方式(chrome.clipboard)は、テキストのコピーに対応していません。

上記の通り Manifest V3 でのクリップボードコピーは、現状八方塞がりです。ですが、アクティブタグにスクリプトを挿入することでこの問題を回避しています。ただし、システム系のタブ(chrome://)などで機能しないなど問題も多くあります。

別解として、新しいタブを開いてスクリプトを挿入する方法があります。より安全にスクリプトを注入できます。ただし、タブのオープン・クローズによる画面のちらつきがあります。

※正式な実装時には、要検討対象です。
Content scripts - Chrome Developers

その他の Manifest V3 の問題

chrome.i18n.getMessage が ServiceWorker で使用できない

chrome.i18n.getMessage がバックグラウンド上の ServiceWorker からアクセスできません。

この問題は、アクションボタンのラベルやコンテキストメニューのラベルの国際化に影響します。

この問題は、まだ解決していませんが、今後解決する可能性がああります。(現在Chrome98)

関連記事

  1. Firefox userChrome.js用ユーザスクリプトを作成する
  2. Firefox用WebExtensions拡張機能を作成する
  3. Chromeの拡張機能を作成する