Codelab: Membuat Ekstensi Chrome di JavaScript menggunakan Gemini

1. Pengantar

Apakah Anda bergabung ke panggilan Meet, tetapi tidak ingin menjadi orang pertama yang melakukannya? Jika Anda adalah orang yang dimaksud, kami punya solusinya!

Setelah mengikuti codelab ini, Anda akan membuat ekstensi Chrome yang memberi tahu Anda saat peserta pertama bergabung ke panggilan.

Anda akan mempelajari berbagai elemen ekstensi Chrome, lalu mempelajari setiap bagian ekstensi secara mendalam. Anda akan mempelajari fungsi ekstensi seperti skrip konten, pekerja layanan, dan penerusan pesan.

Anda harus mematuhi rilis manifes v3 agar dapat menerima notifikasi setiap kali peserta bergabung ke panggilan Meet.

2. Sebelum memulai

Prasyarat

Meskipun codelab ini cocok untuk pemula, memiliki pemahaman dasar tentang Javascript dapat meningkatkan pengalaman Anda.

Penyiapan/Persyaratan

  • Browser Chrome
  • Penyiapan IDE/Editor di sistem lokal Anda.
  • Instal gcloud CLI jika Anda ingin mengaktifkan Gemini API menggunakan gcloud.

Mengaktifkan Gemini API

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. Ayo lacak Sinterklas

Penginstalan Ekstensi Dasar

Mari kita buat direktori yang akan kita gunakan sebagai root project.

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

Sebelum kita mulai mengajukan pertanyaan spesifik kepada Gemini, mari kita ajukan beberapa pertanyaan tentang struktur umum ekstensi Chrome.

Perintah:

What are the important parts to build a chrome extension?

Kita mendapatkan respons yang menentukan detail kecil tentang file manifest, background script, dan detail tentang antarmuka pengguna. Mari kita bahas lebih detail untuk file tertentu ini.

Perintah:

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

Anda dapat menggunakan nama yang diinginkan dan email Anda di kolom penulis.

Gemini menampilkan konten file manifes yang kita butuhkan, tetapi kita mendapatkan beberapa kolom tambahan yang tidak kita perlukan, seperti kolom action. Selain itu, kita memerlukan deskripsi. Ayo perbaiki.

Perintah:

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

Mari kita masukkan konten ini ke dalam file manifest.json di root project Anda.

Pada tahap ini, file manifes akan terlihat seperti ini.

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

Hapus kolom tambahan lainnya yang dibuat di file manifes Anda untuk saat ini karena codelab ini mengasumsikan kolom ini ada di file manifes Anda.

Sekarang, bagaimana cara menguji apakah ekstensi berfungsi? Mari kita tanyakan kepada teman kita, Gemini.

Perintah:

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

Gemini memberikan beberapa langkah tentang cara mengujinya. Mari kita buka "Extensions Page" dengan membuka chrome://extensions dan pastikan untuk mengaktifkan tombol "Developer Mode", yang akan menampilkan tombol "Load unpacked", yang dapat kita gunakan untuk membuka folder yang berisi file ekstensi secara lokal. Setelah melakukannya, kita akan dapat melihat ekstensi di "Extensions Page".

3d802a497ce0cfc2.png

92db1999a1800ecd.png

Bagus! Kita dapat melihat ekstensi kita, tetapi mari kita mulai menambahkan beberapa fungsi.

4. Menambahkan skrip konten

Kita ingin menjalankan beberapa kode JavaScript hanya di https://meet.google.com yang dapat kita lakukan menggunakan skrip konten. Mari kita tanyakan kepada Gemini, cara mencapainya di ekstensi kita.

Perintah:

How to add a content script in our chrome extension?

Atau lebih spesifik:

Perintah:

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

Atau versi lain:

Perintah:

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 memberi kita perubahan persis yang perlu kita lakukan di file manifest.json dan juga JavaScript yang kita butuhkan di file content.js.

Dengan penambahan content_scripts, file manifes kita menjadi:

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

Hal ini memberi tahu Chrome untuk menyisipkan skrip konten content.js setiap kali kita membuka halaman di subdomain " https://meet.google.com". Mari kita tambahkan file ini dan mengujinya.

Mari kita tambahkan kode ini di file content.js.

console.log("Hello Gemini");

Tentu saja! Saat kita membuka meet.google.com, kita melihat "Hello Gemini" di konsol JavaScript(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("Hello Gemini!");

6216bab627c31e6c.png

d61631cd9962ffe5.png

Bagus! Sekarang kita berada dalam posisi di mana kita dapat menambahkan beberapa fungsi khusus JavaScript ke aplikasi kita. Mari kita luangkan waktu sejenak dan pikirkan apa yang ingin kita capai.

Meningkatkan skrip konten

Kita ingin mendapatkan notifikasi saat seseorang bergabung ke rapat saat kita berada di halaman rapat(Tempat kita memiliki opsi untuk bergabung ke rapat). Untuk mencapainya, mari kita amati bagaimana layar berubah secara visual saat rapat kosong vs saat seseorang telah bergabung ke rapat.

Tampilan saat tidak ada orang di rapat.

fe5a0c95b20e7f72.png

Sedangkan ini adalah visual saat ada beberapa peserta di rapat.

7a5ef60521d961cc.png

Kita dapat melihat 2 perbedaan penting sejak awal:

  1. Teks status berubah dari "No one else is here" menjadi "[User] is in this call".
  2. Kita dapat melihat gambar pengguna yang telah bergabung ke panggilan.

Kedua perubahan ini akan berfungsi bagi kita jika kita ingin mengetahui apakah ada orang yang bergabung ke rapat, tetapi perubahan yang terakhir memiliki beberapa kemungkinan untuk mendapatkan informasi tentang pengguna yang telah bergabung, jadi mari kita coba gunakan.

Buka "Elements Inspector" di Chrome dengan tombol pintas ( Mac: Cmd + Opt + C / Win: Ctrl + Shift + C), lalu klik gambar pengguna yang telah bergabung.

Kita dapat melihat bahwa ada gambar dengan beberapa string class dan atribut judul gambar memiliki nama pengguna yang telah bergabung ke rapat. Selain itu, tag gambar ini dienkapsulasi dalam div dengan class U04fid. Setelah kita menambahkan beberapa peserta ke rapat pengujian, kita dapat melihat bahwa div induk ini menghosting beberapa gambar(sesuai dengan pengguna yang berbeda).

Jadi, kita memiliki strategi parsial:

  1. Deteksi saat div dengan class U04fid berisi elemen apa pun.
  2. Jika ada, berarti kita memiliki peserta di rapat.
  3. Beri tahu pengguna.

Mari kita kembali ke Gemini dan tanyakan bagaimana cara mencapai langkah ini langkah demi langkah.

Perintah:

How to detect for element changes in the HTML page?

Gemini memberi kita solusi yang melibatkan MutationObserver, tetapi tidak ada yang spesifik untuk persyaratan kita, mari kita coba ubah perintahnya.

Perintah:

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

Kali ini kita mendapatkan solusi yang tidak menyertakan MutationObserver, tetapi solusi yang memeriksa peserta menggunakan div induk.

Inilah yang kita terima:

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

Mari kita coba ubah pendekatan kita lebih lanjut:

Perintah:

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.

Gemini menampilkan cuplikan kode berikut:

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

Salin kode ini ke dalam file content.js, muat ulang ekstensi(lalu muat ulang halaman Meet).

Sekarang, saat seseorang bergabung ke rapat, kita dapat melihat pernyataan log di konsol.

5. Mengirim notifikasi kepada pengguna

Sekarang kita dapat mendeteksi saat peserta bergabung ke rapat, mari kita coba tambahkan bagian notifikasi di ekstensi Chrome kita. Kita dapat menjelajahi dokumentasi ekstensi Chrome atau bahkan mengubah perintah untuk mengetahui apa yang kita cari, tetapi pada dasarnya kita perlu menggunakan chrome.notifications.create API dan panggilan ke metode ini harus dari pekerja layanan latar belakang.

Perintah:

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

Kita melihat beberapa langkah mendetail dengan sorotan utama:

  • Tambahkan izin notifications di file manifes.
  • Lakukan panggilan ke chrome.notifications.create
  • Panggilan harus berada dalam skrip latar belakang.

Untuk menambahkan skrip latar belakang ke ekstensi Chrome di manifest version 3, kita memerlukan deklarasi background.service_worker di file manifest.json.

Jadi, kita membuat file bernama background.js dan menambahkan hal berikut ke file manifest.json kita.

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

Dengan penambahan di atas, file manifes kita menjadi:

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

Perintah:

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

Simpan gambar ini di root folder Anda dan ganti namanya menjadi success.png.

b2c22f064a3f2d9c.png

Kemudian, tambahkan cuplikan kode berikut ke background.js Anda.

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

Sekarang, muat ulang ekstensi dari halaman ekstensi dan Anda akan segera melihat pop-up notifikasi.

6. Menambahkan penerusan pesan di ekstensi Chrome Anda

Sekarang, langkah utama terakhir yang kita perlukan adalah menghubungkan deteksi peserta skrip konten dan metode sendNotification di skrip latar belakang. Dalam konteks ekstensi Chrome, cara melakukannya adalah melalui teknik yang disebut message passing.

Hal ini memungkinkan komunikasi antara berbagai bagian ekstensi Chrome, dalam kasus kita dari skrip konten ke pekerja layanan latar belakang. Mari kita tanyakan kepada teman kita, Gemini, cara mencapainya.

Perintah:

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

Gemini merespons dengan panggilan yang relevan ke chrome.runtime.sendMessage dan chrome.runtime.onMessage.addListener.

Pada dasarnya, kita akan menggunakan sendMessage untuk mengirim pesan dari skrip konten bahwa seseorang telah bergabung ke panggilan Meet dan onMessage.addListener sebagai pemroses peristiwa untuk bereaksi terhadap pesan yang dikirim oleh skrip konten. Dalam hal ini, kita akan memicu panggilan ke metode sendNotification dari pemroses peristiwa ini.

Kita akan meneruskan pesan notifikasi dan properti action ke pekerja layanan latar belakang. Properti action menjelaskan respons skrip latar belakang.

Jadi, berikut kode content.js kita:

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

Dan ini adalah kode background.js kita:

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

Mari kita coba sesuaikan pesan notifikasi dan dapatkan ID notifikasi yang unik. Untuk pesan notifikasi, kita dapat menyertakan nama pengguna. Jika kita ingat dari langkah sebelumnya, kita dapat melihat nama pengguna di atribut judul gambar. Jadi, kita dapat mengambil nama peserta menggunakan document.querySelector('div.U04fid > img').getAttribute('title').

Terkait ID notifikasi, kita dapat mengambil ID tab skrip konten dan menggunakannya sebagai ID notifikasi. Hal ini dapat dilakukan di dalam pemroses peristiwa chrome.runtime.onMessage.addListener dengan menggunakan sender.tab.id.

Terakhir, file kita akan terlihat seperti ini:

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. Selamat

Dalam waktu singkat, kita dapat membuat ekstensi Chrome dengan bantuan Gemini. Baik Anda adalah developer ekstensi Chrome yang berpengalaman, atau baru mengenal dunia ekstensi,Gemini dapat membantu Anda dengan tugas apa pun yang ingin Anda capai.

Saya mendorong Anda untuk bertanya tentang berbagai hal yang dapat Anda lakukan dengan ekstensi Chrome. Ada banyak API yang layak dijelajahi seperti chrome.storage, alarms, dll. Jika Anda merasa kesulitan, gunakan Gemini atau dokumentasi untuk mengetahui kesalahan Anda atau mengumpulkan berbagai cara untuk memecahkan masalah.

Sering kali, kita perlu mengubah perintah untuk mendapatkan bantuan yang diperlukan, tetapi kita dapat melakukannya dari satu tab yang mempertahankan semua perjalanan kontekstual kita.