1. はじめに
Meet の通話に参加したいけど、一番乗りは避けたいですか?このような場合は、次のソリューションをお試しください。
この Codelab に沿って、最初の参加者が通話に参加したときにアラートを表示する Chrome 拡張機能を作成します。
Chrome 拡張機能のさまざまな要素について学び、拡張機能の各部分について詳しく説明します。コンテンツ スクリプト、サービス ワーカー、メッセージ パッシングなどの拡張機能について説明します。
参加者が Meet 通話に参加するたびに通知を受け取るには、マニフェスト v3 のリリースに準拠する必要があります。
2. 始める前に
前提条件
この Codelab は初心者向けですが、JavaScript の基礎知識があると、よりスムーズに進めることができます。
設定/要件
- Chrome ブラウザ
- ローカル システムに設定された IDE/エディタ。
- gcloud を使用して Gemini API を有効にする場合は、gcloud CLI をインストールします。
Gemini API を有効にする
- Google Cloud コンソールのプロジェクト選択ページで、Google Cloud プロジェクトを選択または作成します。
- Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
- Gemini Marketplace ページに移動して API を有効にします。gcloud を使用して API を有効にすることもできます。
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID - 新しいタブで Gemini for Cloud コンソールのページにアクセスし、[Start chatting] をクリックします。
Note that if you're writing the code in the Cloud Shell editor, then you will have to download the folder somewhere on your local filesystem to test the extension locally.
3. さあ、始めましょう
基本的な拡張機能のインストール
プロジェクトのルートとして使用するディレクトリを作成しましょう。
mkdir gemini-chrome-ext
cd gemini-chrome-ext
Gemini に具体的な質問をする前に、Chrome 拡張機能の一般的な構造について質問してみましょう。
プロンプト:
What are the important parts to build a chrome extension?
manifest ファイル、background script、ユーザー インターフェースの詳細を指定するレスポンスが返されます。これらの特定のファイルについて詳しく見ていきましょう。
プロンプト:
Create a manifest.json file to build a chrome extension. Make the name of the extension "Meet Joinees Notifier" and the author "<YOUR_EMAIL>"
著者フィールドには、任意の名前とメールアドレスを使用できます。
Gemini は必要なマニフェスト ファイルのコンテンツを返しますが、action フィールドなど、不要な追加のフィールドもいくつか返します。説明も必要です。これを解決しましょう。
プロンプト:
Remove the "action" field and make the description as "Adds the ability to receive a notification when a participant joins a Google meet".
このコンテンツをプロジェクトのルートにある manifest.json ファイルに配置しましょう。
この段階では、マニフェスト ファイルは次のようになります。
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>"
}
この Codelab ではマニフェスト ファイルにこれらのフィールドがあることを前提としているため、マニフェスト ファイルで生成されたその他の追加フィールドは、今のところ削除してください。
では、拡張機能が動作することをテストするにはどうすればよいでしょうか。Gemini に聞いてみましょう。
プロンプト:
Guide me on the steps needed to test a chrome extension on my local filesystem.
テスト方法の手順は示されています。chrome://extensions に移動して "Extensions Page" に移動し、"Developer Mode" ボタンが有効になっていることを確認します。これにより、"Load unpacked" ボタンが表示されます。このボタンを使用して、拡張機能ファイルがローカルに保存されているフォルダに移動できます。この操作を行うと、"Extensions Page" に拡張機能が表示されるようになります。


これで、拡張機能が表示されましたが、機能を追加していきましょう。
4. コンテンツ スクリプトを追加する
コンテンツ スクリプトを使用して、https://meet.google.com でのみ実行する JavaScript コードを作成します。拡張機能でこれを実現する方法を Gemini に尋ねてみましょう。
プロンプト:
How to add a content script in our chrome extension?
または、より具体的に次のように指定します。
プロンプト:
How to add a content script to run on meet.google.com subdomain in our chrome extension?
別のバージョン:
プロンプト:
Help me add a content script named content.js to run on meet.google.com subdomain in our chrome extension. The content script should simply log "Hello Gemini" when we navigate to "meet.google.com".
Gemini は、manifest.json ファイルで行う必要のある変更と、content.js ファイルで必要な JavaScript を正確に示してくれます。
content_scripts を追加すると、マニフェスト ファイルは次のようになります。
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "abc@example.com",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
]
}
これは、サブドメイン「https://meet.google.com」のページに移動するたびに、コンテンツ スクリプト content.js を挿入するよう Chrome に指示します。このファイルを追加してテストしてみましょう。
このコードを content.js ファイルに追加しましょう。
console.log("Hello Gemini");
そのとおりです。meet.google.com にアクセスすると、JavaScript コンソール(Mac: Cmd + Opt + J / Win/Linux: Ctrl + Shift + J)に「Hello Gemini」と表示されます。
manifest.json
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "luke@cloudadvocacyorg.joonix.net",
"permissions": [
"tabs",
"notifications"
],
"content_scripts": [
{
"matches": [
"https://meet.google.com/*"
],
"js": [
"content.js"
]
}
]
}
content.js
console.log("Hello Gemini!");


これで、これで、アプリに JavaScript 固有の機能を追加できるようになりました。ここで、達成しようとしていることを確認しましょう。
コンテンツ スクリプトの改善
会議ページ(会議に参加するオプションがあるページ)で、他のユーザーが会議に参加したときに通知を受け取れるようにしてほしい。これを実現するために、会議が空の場合と誰かが会議に参加した場合で、画面がどのように変化するかを見てみましょう。
ミーティングに誰も参加していない場合は、次のように表示されます。

会議に一部の参加者がいる場合のビジュアルは次のようになります。

すぐに 2 つの大きな違いがわかります。
- ステータス テキストが「他の参加者はいません」から「[ユーザー] が通話に参加しています」に変わります。
- 通話に参加しているユーザーの画像が表示されます。
どちらの変更でも、会議に参加したユーザーがいるかどうかを確認できますが、後者の変更では、すでに参加しているユーザーに関する情報を取得できる可能性があるため、後者の変更を使用してみましょう。
ホットキー(Mac: Cmd + Opt + C / Win: Ctrl + Shift + C)を使用して Chrome で [要素の検査] を開き、参加したユーザーの画像をクリックします。
クラス文字列が少ない画像があり、その画像の title 属性には会議に参加したユーザーの名前が含まれていることがわかります。さらに、この画像タグはクラス U04fid の div でラップされています。テスト会議に何人か参加者を追加すると、この親 div に複数の画像(異なるユーザーに対応)がホストされていることがわかります。
そこで、次のような部分的な戦略を考えました。
- クラス
U04fidの div に要素が含まれているかどうかを検出します。 - 参加者がいる場合は、会議にジョインしていることを意味します。
- ユーザーに通知します。
Gemini に戻って、この手順を段階的に実行する方法を尋ねてみましょう。
プロンプト:
How to detect for element changes in the HTML page?
MutationObserver を含むソリューションは得られましたが、要件に固有のものは得られませんでした。プロンプトを変更してみましょう。
プロンプト:
How can I detect if an element "div.U04fid" has any child images in the HTML page?
今回は、MutationObserver を含まないソリューション、つまり親 div を使用して参加者をチェックするソリューションを取得します。
お送りいただいた内容は以下のとおりです。
const divU04fid = document.querySelector('div.U04fid');
const childImages = divU04fid.querySelectorAll('img');
if (childImages.length > 0) {
// div.U04fid has at least one child image.
}
アプローチをさらに変更してみましょう。
プロンプト:
Create a method which checks if the element div.U04fid has any child elements, if it does it should log it on the console. The method should be called checkJoinees and it should be called as a callback for MutationObserver which is observing the document.body.
次のコード スニペットが返されます。
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
// div.U04fid has at least one child element.
console.log('div.U04fid has at least one child element.');
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
このコードを content.js ファイルにコピーし、拡張機能を再読み込みします(次に、Meet のページを再読み込みします)。
これで、会議に参加したユーザーのログステートメントがコンソールに表示されるようになりました。
5. ユーザーに通知を送信する
参加者が会議に参加したことを検出できるようになったので、Chrome 拡張機能に通知部分を追加してみましょう。Chrome 拡張機能のドキュメントを参照したり、プロンプトを調整して探しているものを把握したりできますが、基本的には chrome.notifications.create API を使用する必要があります。このメソッドの呼び出しはバックグラウンド サービス ワーカーから行う必要があります。
プロンプト:
Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.
主なハイライトは次のとおりです。
- マニフェスト ファイルに
notifications権限を追加します。 - chrome.notifications.create を呼び出す
- 呼び出しはバックグラウンド スクリプト内で行う必要があります。
manifest version 3 で Chrome 拡張機能にバックグラウンド スクリプトを追加するには、manifest.json ファイルに background.service_worker 宣言が必要です。
そこで、background.js というファイルを作成し、manifest.json ファイルに以下を追加します。
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
上記を追加すると、マニフェスト ファイルは次のようになります。
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
}
プロンプト:
Create a method sendNotification that calls the chrome.notifications.create method with the message, "A user joined the call" for a chrome extension with manifest v3, the code is in the background service worker
この画像をフォルダのルートに保存し、名前を success.png に変更します。

次に、以下のコード スニペットを background.js に追加します。
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
sendNotification("notif-id", "test message");
拡張機能ページから拡張機能を再読み込みすると、すぐに通知ポップアップが表示されます。
6. Chrome 拡張機能にメッセージ パッシングを追加する
最後に、コンテンツ スクリプトによる参加者の検出と、バックグラウンド スクリプトの sendNotification メソッドを接続する必要があります。Chrome 拡張機能のコンテキストでは、message passing という手法を使用します。
これにより、Chrome 拡張機能のさまざまな部分(この場合はコンテンツ スクリプトからバックグラウンド サービス ワーカー)間の通信が可能になります。Gemini にその方法を尋ねてみましょう。
プロンプト:
How to send a message from the content script to the background script in a chrome extension
Gemini は、chrome.runtime.sendMessage と chrome.runtime.onMessage.addListener への関連する呼び出しを返します。
基本的には、sendMessage を使用して、コンテンツ スクリプトから会議通話に参加したことを示すメッセージを送信し、onMessage.addListener をイベント リスナーとして使用して、コンテンツ スクリプトから送信されたメッセージに応答します。この場合、このイベント リスナーから sendNotification メソッドの呼び出しをトリガーします。
通知メッセージと action プロパティをバックグラウンド サービス ワーカーに渡します。action プロパティは、バックグラウンド スクリプトが何に応答しているかを示します。
content.js コードは次のようになります。
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
// div.U04fid has at least one child element.
sendMessage();
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
function sendMessage() {
chrome.runtime.sendMessage({
txt: "A user has joined the call!",
action: "people_joined"
});
}
background.js コードは次のとおりです。
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "people_joined") {
sendNotification("notif-id", message.txt);
}
});
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
通知メッセージをカスタマイズして、一意の通知 ID を取得してみましょう。通知メッセージには、ユーザーの名前を含めることができます。前の手順で確認したように、画像の title 属性にユーザーの名前が表示されます。したがって、document.querySelector('div.U04fid > img').getAttribute('title'). を使用して参加者の名前を取得できます。
通知 ID については、コンテンツ スクリプトのタブ ID を取得して、それを通知 ID として使用できます。これは、sender.tab.id. を使用してイベント リスナー chrome.runtime.onMessage.addListener 内で実現できます。
最終的に、ファイルは次のようになります。
manifest.json
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
}
content.js
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
const name = document.querySelector('div.U04fid > img').getAttribute('title');
sendMessage(name);
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
function sendMessage(name) {
const joinee = (name === null ? 'Someone' : name),
txt = `${joinee} has joined the call!`;
chrome.runtime.sendMessage({
txt,
action: "people_joined",
});
}
background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "people_joined") {
sendNotification("" + sender.tab.id, message.txt); // We are casting this to string as notificationId is expected to be a string while sender.tab.id is an integer.
}
});
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
7. 完了
Gemini の助けを借りて、短時間で Chrome 拡張機能を構築できました。Chrome 拡張機能の開発経験がある方も、拡張機能の世界に初めて触れる方も、Gemini はあらゆるタスクの達成をサポートします。
Chrome 拡張機能でできることについて、ぜひお尋ねください。chrome.storage や alarms など、参照する価値のある API はたくさんあります。行き詰まったときは、Gemini またはドキュメントを使用して、何が間違っているのかを把握したり、問題を解決するためのさまざまな方法を収集したりしてください。
必要なヘルプを得るには、プロンプトの変更が必要になることがよくありますが、コンテキスト ジャーニー全体が保持された 1 つのタブから変更できます。