Codelab: Mit Gemini eine Chrome-Erweiterung in JavaScript erstellen

1. Einführung

Nehmen Sie an einem Meet-Anruf teil, möchten aber nicht der Erste sein? Wenn dies auf Sie zutrifft, haben wir die Lösung für Sie.

Nach diesem Codelab erstellen Sie eine Chrome-Erweiterung, die Sie benachrichtigt, wenn der erste Teilnehmer am Anruf teilnimmt.

Sie lernen die verschiedenen Elemente von Chrome-Erweiterungen kennen und sehen uns die einzelnen Bestandteile dann genauer an. Sie lernen Erweiterungsfunktionen wie Inhaltsskripte, Service Worker und die Nachrichtenweitergabe kennen.

Sie müssen sich an die Version 3 des Manifests halten, um jedes Mal eine Benachrichtigung zu erhalten, wenn ein Teilnehmer an einem Meet-Anruf teilnimmt.

2. Hinweis

Vorbereitung

Dieses Codelab ist zwar für Einsteiger geeignet, ein grundlegendes Verständnis von JavaScript kann jedoch zu erheblichen Verbesserungen bei der Nutzung führen.

Einrichtung/Anforderungen

  • Chrome-Browser
  • Eine IDE/ein Editor, die auf Ihrem lokalen System eingerichtet ist.
  • Installieren Sie gcloud cli, wenn Sie die Gemini API mit gcloud aktivieren möchten.

Gemini API aktivieren

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. Los gehts

Grundlegende Installation von Erweiterungen

Lassen Sie uns ein Verzeichnis erstellen, das wir als Stammverzeichnis Ihres Projekts verwenden.

mkdir gemini-chrome-ext
cd gemini-chrome-ext

Bevor wir konkrete Fragen an Gemini stellen, sollten wir einige Fragen zur allgemeinen Struktur einer Chrome-Erweiterung stellen.

Prompt:

What are the important parts to build a chrome extension?

Wir erhalten eine Antwort mit kleineren Details zur Datei manifest, zum background script und Details zur Benutzeroberfläche. Sehen wir uns diese Dateien etwas genauer an.

Prompt:

Create a manifest.json file to build a chrome extension.
Make the name of the extension "Meet Joinees Notifier"
and the author "<YOUR_EMAIL>"

Sie können einen gewünschten Namen und Ihre E-Mail-Adresse im Feld für den Autor eingeben.

Gemini gibt den benötigten Inhalt der Manifestdatei zurück, aber wir erhalten einige zusätzliche Felder, die wir nicht benötigen, z. B. das Feld action. Außerdem benötigen wir eine Beschreibung. Das sollte nicht sein.

Prompt:

Remove the "action" field and make the description as
"Adds the ability to receive a notification when a participant joins a Google meet".

Fügen Sie diesen Inhalt in die Datei manifest.json im Stammverzeichnis Ihres Projekts ein.

Die Manifestdatei sollte nun in etwa so aussehen:

{
    "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>"
}

Entfernen Sie vorerst alle zusätzlichen Felder, die in Ihrer Manifestdatei generiert wurden, da in diesem Codelab von diesen Feldern in Ihrer Manifestdatei ausgegangen wird.

Wie testen wir nun, ob die Erweiterung funktioniert? Fragen wir unsere Freundin Gemini, ok?

Prompt:

Guide me on the steps needed to test a chrome extension on my local filesystem.

Es gibt mir einige Schritte, wie ich es testen kann. Rufen Sie die "Extensions Page" auf, indem Sie zu chrome://extensions gehen. Achten Sie darauf, die Schaltfläche "Developer Mode" zu aktivieren. Dadurch sollte die Schaltfläche "Load unpacked" angezeigt werden, mit der wir zum Ordner wechseln können, der lokal die Erweiterungsdateien enthält. Danach sollten wir die Erweiterung in "Extensions Page" sehen können.

3d802a497ce0cfc2.png

92db1999a1800ecd.png

Sehr gut! Wir sehen unsere Erweiterung, fügen aber jetzt einige Funktionen hinzu.

4. Inhaltsskript hinzufügen

Wir möchten JavaScript-Code nur auf https://meet.google.com ausführen, was wir mithilfe von Inhaltsskripten tun können. Fragen wir Gemini, wie wir das mit unserer Erweiterung erreichen können.

Prompt:

How to add a content script in our chrome extension?

Oder genauer:

Prompt:

How to add a content script to run on meet.google.com subdomain in our chrome extension?

Oder eine andere Version:

Prompt:

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 liefert uns die genauen Änderungen, die wir an der Datei „manifest.json“ und im JavaScript-Code in der content.js-Datei vornehmen müssen.

Durch das Hinzufügen von „content_scripts“ wird unsere Manifestdatei zu:

{
    "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"]
        }
    ]
}

Dadurch wird Chrome angewiesen, das Content-Skript content.js jedes Mal einzuschleusen, wenn wir eine Seite der Subdomain aufrufen https://meet.google.com“. Lassen Sie uns diese Datei hinzufügen und testen, oder?

Fügen wir diesen Code in die Datei content.js ein.

console.log("Hello Gemini");

Ja, klar. Wenn wir meet.google.com aufrufen, sehen wir „Hallo Gemini“ in der JavaScript-Konsole(Mac: Cmd + Opt + J / Win/Linux: Ctrl + Shift + J).

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("Hallo Gemini!").

à 6216bab627c31e6c.png

d61631cd9962ffe5.png

Sehr gut! Jetzt können wir unserer App JavaScript-spezifische Funktionen hinzufügen. Nehmen wir uns einen Moment Zeit, um darüber nachzudenken, was wir erreichen möchten.

Script für Inhalte optimieren

Wir möchten eine Benachrichtigung erhalten, wenn jemand an einer Besprechung teilnimmt, wenn wir uns auf der Besprechungsseite befinden(wo wir die Möglichkeit haben, an der Besprechung teilzunehmen). Dazu sehen wir uns an, wie sich der Bildschirm visuell verändert, wenn die Besprechung leer ist und wenn jemand der Besprechung beigetreten ist.

So sieht es aus, wenn niemand im Meeting ist.

fe5a0c95b20e7f72.png

Dagegen sind dies die visuellen Elemente, wenn einige Teilnehmer an dem Meeting teilnehmen.

7a5ef60521d961cc.png

Zwei wichtige Unterschiede sind sofort erkennbar:

  1. Der Statustext ändert sich von „Keine andere Person ist hier“. zu „[Nutzer] nimmt an diesem Anruf teil“.
  2. Wir sehen die Bilder der Nutzer, die am Anruf teilnehmen.

Beide Änderungen sind für uns geeignet, wenn wir wissen möchten, ob jemand der Besprechung beigetreten ist. Letzteres hat jedoch einige Möglichkeiten, Informationen über die Nutzer abzurufen, die bereits beigetreten sind. Versuchen wir also, diese zu verwenden.

Elements Inspector öffnen in Chrome mit dem Hotkey ( Mac: Cmd + Opt + C / Win: Ctrl + Shift + C) und klicken Sie dann auf das Bild des beigetretenen Nutzers.

Wir sehen, dass ein Bild mit wenigen Klassenzeichenfolgen vorhanden ist und das Titelattribut des Bildes den Namen des Nutzers enthält, der an der Besprechung teilnimmt. Darüber hinaus ist dieses Bild-Tag in ein div-Element der Klasse U04fid eingeschlossen. Nachdem wir einige Teilnehmer zu unserer Testbesprechung hinzugefügt haben, sehen wir, dass dieses übergeordnete div-Element mehrere Images hostet, die verschiedenen Nutzern entsprechen.

Wir haben also eine Teilstrategie im Kopf:

  1. Erkennt, wenn das div-Element mit der Klasse U04fid Elemente enthält.
  2. Wenn dies der Fall ist, bedeutet das, dass wir Teilnehmer an unserem Meeting haben.
  3. Benachrichtigen Sie den Nutzer.

Kehren wir zu Gemini zurück und fragen wir, wie wir dies Schritt für Schritt erreichen können.

Prompt:

How to detect for element changes in the HTML page?

Es liefert uns eine Lösung mit MutationObserver, aber nichts speziell für unsere Anforderung. Versuchen wir, den Prompt zu ändern.

Prompt:

How can I detect if an element "div.U04fid" has any child images in the HTML page?

Dieses Mal erhalten wir eine Lösung, die MutationObserver nicht enthält, sondern eine Lösung, die mithilfe des übergeordneten div-Elements nach den Joinees sucht.

Wir haben Folgendes erhalten:

const divU04fid = document.querySelector('div.U04fid');
const childImages = divU04fid.querySelectorAll('img');
if (childImages.length > 0) {
  // div.U04fid has at least one child image.
}

Versuchen wir, unseren Ansatz noch weiter zu modifizieren:

Prompt:

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.

Sie gibt das folgende Code-Snippet zurück:

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
});

Kopieren Sie diesen Code in die Datei content.js, aktualisieren Sie die Erweiterung und aktualisieren Sie dann die Meet-Seite.

Wenn jetzt jemand an unserer Besprechung teilnimmt, sehen wir die Protokollanweisung in der Konsole.

5. Benachrichtigung an den Nutzer senden

Jetzt können wir erkennen, wenn ein Teilnehmer der Videokonferenz beigetreten ist. Als Nächstes fügen wir der Chrome-Erweiterung den Benachrichtigungsteil hinzu. Wir können in der Dokumentation der Chrome-Erweiterung nachsehen oder sogar die Eingabeaufforderungen optimieren, um zu wissen, wonach wir suchen. Im Wesentlichen müssen wir jedoch die chrome.notifications.create API verwenden und der Aufruf dieser Methode sollte von einem Hintergrunddienst-Worker stammen.

Prompt:

Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.

Wir sehen hier einige detaillierte Schritte. Die wichtigsten sind:

  • Fügen Sie der Manifestdatei die Berechtigung notifications hinzu.
  • Rufen Sie chrome.notifications.create auf.
  • Der Aufruf sollte sich in einem Hintergrundskript befinden.

Um einer Chrome-Erweiterung in manifest version 3 ein Hintergrundskript hinzuzufügen, benötigen wir die background.service_worker-Deklaration in unserer manifest.json-Datei.

Also erstellen wir eine Datei namens background.js und fügen der Datei „manifest.json“ Folgendes hinzu:

"background": {
        "service_worker": "background.js"
},
"permissions": [
        "notifications"
]

Durch die oben genannten Ergänzungen wird unsere Manifestdatei zu:

{
    "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"
    ]
}

Prompt:

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

Speichern Sie das Bild im Stammverzeichnis Ihres Ordners und benennen Sie es in success.png um.

b2c22f064a3f2d9c.png

Fügen Sie dann das folgende Code-Snippet in die Datei background.js ein.

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");

Wenn Sie die Erweiterung jetzt über die Seite „Erweiterungen“ aktualisieren, sollte sofort ein Pop-up-Benachrichtigungs-Pop-up angezeigt werden.

6. Nachrichtenübergabe in der Chrome-Erweiterung hinzufügen

Der letzte große Schritt besteht darin, die Erkennung eines Teilnehmers durch das Inhaltsskript mit der Methode sendNotification im Hintergrundskript zu verbinden. Bei Chrome-Erweiterungen erfolgt dies über eine Technik namens message passing.

Dies ermöglicht die Kommunikation zwischen verschiedenen Teilen einer Chrome-Erweiterung, in unserem Fall vom Content-Skript bis zum Hintergrund-Service-Worker. Fragen wir Gemini, wie das geht.

Prompt:

How to send a message from the content script to the background script in a chrome extension

Gemini antwortet mit relevanten Anrufen an chrome.runtime.sendMessage und chrome.runtime.onMessage.addListener.

Im Wesentlichen verwenden wir sendMessage, um über das Inhaltsskript eine Nachricht zu senden, dass eine Person am Meet-Anruf teilnimmt, und onMessage.addListener als Ereignis-Listener, um auf die vom Inhaltsskript gesendete Nachricht zu reagieren. In diesem Fall lösen wir den Aufruf der Methode sendNotification von diesem Ereignis-Listener aus.

Wir übergeben die Benachrichtigung und die Eigenschaft action an den Hintergrund-Service-Worker. Die Eigenschaft action beschreibt, worauf das Hintergrundskript reagiert.

Hier ist also unser content.js-Code:

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"
    });
}

Und das ist unser background.js-Code:

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"
    });
}

Versuchen wir, die Benachrichtigungsnachricht anzupassen, um eine eindeutige Benachrichtigungs-ID zu erhalten. In der Benachrichtigungsnachricht können wir den Namen des Nutzers angeben. Wenn wir uns aus einem vorherigen Schritt erinnern, können wir den Namen des Nutzers im Titelattribut des Bildes sehen. Wir können also den Namen des Teilnehmers mithilfe von document.querySelector('div.U04fid > img').getAttribute('title'). abrufen.

In Bezug auf die Benachrichtigungs-ID können wir die Tab-ID des Content-Skripts abrufen und als Benachrichtigungs-ID verwenden. Hierzu können Sie in unserem Event-Listener chrome.runtime.onMessage.addListener die Funktion sender.tab.id. verwenden.

Die Dateien sollten in etwa so aussehen:

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. Glückwunsch

In kurzer Zeit konnten wir mithilfe von Gemini eine Chrome-Erweiterung erstellen. Ganz gleich, ob du ein erfahrener Entwickler von Chrome-Erweiterungen bist oder noch keine Erfahrung mit Erweiterungen hast – Gemini kann dir bei allen Aufgaben helfen,die du erreichen möchtest.

Ich empfehle Ihnen, sich nach den verschiedenen Möglichkeiten zu erkundigen, die eine Chrome-Erweiterung bietet. Es gibt viele APIs, die sich lohnen, z. B. chrome.storage oder alarms. Wenn du nicht weiterkommst, verwende Gemini oder die Dokumentation, um zu erfahren, was du falsch machst, oder um verschiedene Lösungsmöglichkeiten zu finden.

Oft müssen Prompts angepasst werden, um die benötigte Hilfe zu erhalten. Wir können dies aber über einen Tab tun, auf dem alle unsere kontextbezogenen Schritte gespeichert bleiben.