はじめに (対象読者・この記事でわかること)

この記事は、ブラウザ拡張機能の開発に興味があるWeb開発者、特にChromiumベースのブラウザ(Chrome、Edgeなど)向けの拡張機能を作成したい人を対象としています。この記事を読むことで、Chromiumベースのブラウザ拡張機能で実行環境であるブラウザを判別する方法を理解できます。具体的には、chrome.runtime APIやwindow.navigator.userAgentを使用した判別方法、ブラウザ固有のAPIの存在確認による判別方法などを実装できます。また、ブラウザ固有の機能を適切に利用するためのベストプラクティスも学べます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - JavaScriptの基本的な知識 - Chrome拡張機能の基本的な構造とmanifest.jsonの理解 - 非同期処理(Promiseやasync/await)の理解

Chromiumベースブラウザの拡張機能と判別の必要性

Chromiumベースのブラウザ(Google Chrome、Microsoft Edge、Brave、Vivaldiなど)は共通の技術基盤を持っています。そのため、基本的にはChrome拡張機能として開発したものを各ブラウザで動作させることができます。しかし、各ブラウザには独自の機能やAPIが存在し、ブラウザ固有の挙動を扱いたい場合があります。例えば、Microsoft Edge固有の機能や、特定のブラウザ向けの最適化を行いたい場合です。

また、ブラウザによってユーザーエージェントやサポートされているAPIが異なるため、実行環境を正確に判別することが重要です。判別を行うことで、以下のようなメリットがあります。

  1. ブラウザ固有のAPIを安全に利用できる
  2. ブラウザごとの最適化が可能になる
  3. 互換性の問題を事前に回避できる
  4. デバッグ時の環境特定が容易になる

この記事では、Chromiumベースの拡張機能で実行ブラウザを判別する具体的な方法をいくつか紹介します。

ブラウザ判別の具体的な実装方法

ここでは、Chromiumベースの拡張機能で実行ブラウザを判別する具体的な方法を紹介します。主に3つの方法を取り上げます。

ユーザーエージェントによる判別

最も基本的な方法は、ユーザーエージェント(User Agent)を使用して判別する方法です。JavaScriptではnavigator.userAgentプロパティからユーザーエージェント文字列を取得できます。

Javascript
function getBrowserFromUserAgent() { const userAgent = navigator.userAgent; if (userAgent.includes('Edg/')) { return 'Microsoft Edge'; } else if (userAgent.includes('Chrome/') && !userAgent.includes('Edg/')) { return 'Google Chrome'; } else if (userAgent.includes('Brave/')) { return 'Brave'; } else if (userAgent.includes('Vivaldi/')) { return 'Vivaldi'; } else { return 'Other'; } } const browser = getBrowserFromUserAgent(); console.log(`実行ブラウザ: ${browser}`);

この方法の利点は、非常にシンプルで実装が容易な点です。しかし、ユーザーエージェント文字列はブラウザのバージョンによって変わる可能性があり、将来的に変更されることも考えられます。また、一部のブラウザは他のブラウザのユーザーエージェントを偽装している場合があるため、100%正確とは限りません。

ブラウザ固有のAPIの存在確認による判別

より確実な方法は、ブラウザ固有のAPIが存在するかどうかを確認する方法です。各ブラウザには他のブラウザには実装されていない独自のAPIが存在することがあります。

Javascript
function getBrowserFromAPI() { // Microsoft Edge固有のAPIを確認 if ('msBrowser' in window || 'edge' in window) { return 'Microsoft Edge'; } // Chrome固有のAPIを確認 if ('chrome' in window && !('msBrowser' in window) && !('edge' in window)) { return 'Google Chrome'; } // Brave固有のAPIを確認 if ('brave' in window) { return 'Brave'; } // Vivaldi固有のAPIを確認 if ('vivaldi' in window) { return 'Vivaldi'; } return 'Other'; } const browser = getBrowserFromAPI(); console.log(`実行ブラウザ: ${browser}`);

この方法は、ユーザーエージェントによる判別よりも確実ですが、ブラウザが独自に実装するAPIに依存するため、将来的に変更される可能性もあります。また、すべてのブラウザに固有のAPIが存在するわけではないため、判別できない場合もあります。

chrome.runtime APIによる判別

Chromiumベースの拡張機能では、chrome.runtime APIを使用してブラウザを判別することもできます。このAPIは拡張機能内で利用できる特殊なAPIです。

Javascript
function getBrowserFromChromeRuntime() { if (!chrome || !chrome.runtime) { return 'Not a Chromium extension'; } // Microsoft Edgeの拡張機能では、特定のプロパティが存在する if (chrome.runtime.getURL) { const url = chrome.runtime.getURL(''); if (url.includes('edge-extension://')) { return 'Microsoft Edge'; } } // Chromeの拡張機能では、特定のプロパティが存在する if (chrome.runtime.id) { return 'Google Chrome'; } return 'Other'; } const browser = getBrowserFromChromeRuntime(); console.log(`実行ブラウザ: ${browser}`);

この方法は、拡張機能内で実行される場合にのみ有効ですが、比較的確実な判別が可能です。

判別ロジックの組み合わせ

単一の判別方法に依存するのではなく、複数の方法を組み合わせることで、より確実な判別が可能になります。以下に、ユーザーエージェントとAPIの存在確認を組み合わせた例を示します。

Javascript
function getBrowser() { // ユーザーエージェントによる判別 const userAgent = navigator.userAgent; let browser = 'Other'; if (userAgent.includes('Edg/')) { browser = 'Microsoft Edge'; } else if (userAgent.includes('Chrome/') && !userAgent.includes('Edg/')) { browser = 'Google Chrome'; } else if (userAgent.includes('Brave/')) { browser = 'Brave'; } else if (userAgent.includes('Vivaldi/')) { browser = 'Vivaldi'; } // APIによる判別で上書き if ('msBrowser' in window || 'edge' in window) { browser = 'Microsoft Edge'; } else if ('chrome' in window && !('msBrowser' in window) && !('edge' in window)) { browser = 'Google Chrome'; } else if ('brave' in window) { browser = 'Brave'; } else if ('vivaldi' in window) { browser = 'Vivaldi'; } return browser; } const browser = getBrowser(); console.log(`実行ブラウザ: ${browser}`);

ブラウザのバージョン情報の取得

ブラウザのバージョンによってサポートされているAPIが異なる場合があるため、バージョン情報も考慮に入れるとより正確な判別が可能です。

Javascript
function getBrowserWithVersion() { const userAgent = navigator.userAgent; const match = userAgent.match(/(Chrome|Edg|Brave|Vivaldi)\/(\d+\.\d+\.\d+\.\d+)/); if (match) { return { browser: match[1] === 'Edg' ? 'Microsoft Edge' : match[1], version: match[2] }; } return { browser: 'Other', version: 'Unknown' }; } const browserInfo = getBrowserWithVersion(); console.log(`実行ブラウザ: ${browserInfo.browser} バージョン: ${browserInfo.version}`);

ハマった点やエラー解決

ブラウザ判別の実装中に遭遇する問題として、以下のようなものがあります。

  1. ユーザーエージェントの変化: ブラウザのバージョンアップによりユーザーエージェント文字列が変更される可能性があります。特に、Microsoft EdgeはChromiumベースに移行した際にユーザーエージェントの形式が大きく変更されました。

  2. APIの非互換性: ブラウザによっては、特定のAPIが実装されていない場合があります。また、APIの実装が異なる場合もあります。

  3. 拡張機能のコンテキスト: 拡張機能のバックグラウンドスクリプト、コンテンツスクリプト、ポップアップなど、実行されるコンテキストによって利用できるAPIが異なる場合があります。

解決策

これらの問題を解決するためのベストプラクティスを以下に示します。

  1. 複数の方法を組み合わせる: 先述の通り、単一の判別方法に依存するのではなく、複数の方法を組み合わせることで、より確実な判別が可能になります。

  2. デフォルトフォールバックを用意する: 判別できない場合に備えて、デフォルトの挙動を用意しておきます。たとえば、ChromeとEdgeは互換性が高いため、判別できなかった場合はChromeと同じ処理を実行するようにします。

Javascript
function getBrowserOrDefault() { const browser = getBrowser(); // 前述の組み合わせ判別関数 // 判別できない場合のデフォルト処理 if (browser === 'Other') { // ChromeとEdgeは互換性が高いため、Chromeと同じ処理を実行 return 'Chrome'; } return browser; }
  1. ユニットテストを作成する: 判別ロジックが正しく動作するかを確認するため、各ブラウザで実行されるユニットテストを作成します。これにより、将来的な変更による不具合を早期に発見できます。
Javascript
// ユニットテストの例 function testBrowserDetection() { // モックのユーザーエージェントを設定 Object.defineProperty(navigator, 'userAgent', { value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59', configurable: true }); // モックのAPIを設定 global.window = { ...window, chrome: { runtime: { getURL: () => 'edge-extension://abcd1234/' } } }; // 判別テスト const browser = getBrowser(); console.assert(browser === 'Microsoft Edge', 'Edgeの判別に失敗'); console.log('テスト完了'); } testBrowserDetection();
  1. バージョンに応じた条件分岐を行う: ブラウザのバージョンによってサポートされているAPIが異なる場合があるため、バージョン情報を取得して条件分岐を行います。
Javascript
function useBrowserSpecificAPI() { const browserInfo = getBrowserWithVersion(); // Microsoft Edge 91以上の場合のみ特定のAPIを使用 if (browserInfo.browser === 'Microsoft Edge') { const versionParts = browserInfo.version.split('.').map(Number); if (versionParts[0] > 91 || (versionParts[0] === 91 && versionParts[1] >= 0)) { // Edge 91以上で利用可能なAPIを使用 return 'Edge specific API'; } } // その他のブラウザまたは古いEdgeの場合 return 'Common API'; }

まとめ

本記事では、Chromiumベースのブラウザ拡張機能で実行ブラウザを判別する方法を紹介しました。ユーザーエージェントの確認、ブラウザ固有APIの存在確認、chrome.runtime APIの利用といった方法を取り上げ、それぞれの利点と欠点を説明しました。また、判別中に遭遇する問題とその解決策についても触れました。

  • ユーザーエージェントによる判別はシンプルですが、将来的に変更される可能性がある
  • ブラウザ固有APIの存在確認は確実だが、すべてのブラウザに固有のAPIが存在するわけではない
  • 複数の方法を組み合わせることで、より確実な判別が可能
  • 判別できない場合のデフォルト挙動を用意しておくことが重要

この記事を通して、ブラウザ拡張機能の開発者が実行環境を正確に判別するための知識を得られたと思います。今後は、ブラウザ固有の機能を活用した拡張機能の実装についても記事にする予定です。

参考資料