Chrome 拡張機能(Manifest v3)で開いてるタブに対して文字列でJSを実行する方法

に公開

まえがき

もともとManifest v2で開発していたものがあり、v3にアップデートするのが面倒で放置していたらついに使えなくなってしまいやむを得ずアップデートすることにしました。
その時、基本的には マイグレーションガイド の通りにやって動いたのですが、 chrome.tabs.executeScript で対象のタブに文字列でjsを実行している部分だけうまく実行することができませんでした。

コードの例

v2 のコード

もともとこんな感じだったものを


chrome.tabs.executeScript(tabId, {
  code: "ユーザーが設定した文字列で書かれたjsのコード",
}, function () {
  if (chrome.runtime.lastError) {
    console.error(chrome.runtime.lastError.message);
  }
  else {
    close();
  }
});

こんな感じに変更したのですが、evalがダメなので動きませんでした。

v3 のコード(動かない)

chrome.scripting.executeScript({
  target: { tabId },
  args: ["ユーザーが設定した文字列で書かれたjsのコード"],
  func: (arg) => {
    eval(arg);
  },
}, function () {
  if (chrome.runtime.lastError) {
    console.error(chrome.runtime.lastError.message);
  }
  else {
    close();
  }
});

どうすれば動くのか

色々調べた結果 userScripts という機能があり、それを使うと動くようです。
ただし設定が必要で、拡張機能インストール後に、拡張機能の詳細画面から 「ユーザー スクリプトを許可する」を有効にする必要があります。

ユーザー スクリプトを許可する

詳しい手順については、公式ドキュメントに書いてあるので、そちらを参照してください。(丸投げ)

https://developer.chrome.com/docs/extensions/reference/api/userScripts?hl=ja

動くコード


if (!chrome.userScripts) {
  alert('拡張機能の設定画面から「ユーザー スクリプトを許可する」を有効にしてください。');
  return;
}

await chrome.userScripts.execute({
  js: [{ code: "ユーザーが設定した文字列で書かれたjsのコード" }],
  world: 'MAIN',
  target: { tabId },
  injectImmediately: true
}).catch((e) => {
  console.error(e.message);
});

close();

あとがき

この部分だけマイグレーションにだいぶ手こずったので、同じ内容で困っている人の参考になれば幸いです。

Discussion