Lớp học lập trình: Tạo tiện ích của Chrome trong JavaScript bằng Gemini

1. Giới thiệu

Bạn đang tham gia cuộc gọi trên Meet nhưng không muốn là người đầu tiên tham gia? Nếu đây là trường hợp của bạn, thì chúng tôi có giải pháp dành cho bạn!

Sau lớp học lập trình này, bạn sẽ tạo một tiện ích của Chrome để cảnh báo bạn khi người tham gia đầu tiên tham gia cuộc gọi.

Bạn sẽ tìm hiểu các thành phần khác nhau của một tiện ích của Chrome, sau đó nghiên cứu chuyên sâu vào từng phần của tiện ích. Bạn sẽ tìm hiểu về các hàm của tiện ích, chẳng hạn như tập lệnh nội dung, trình thực thi dịch vụ và truyền thông báo.

Bạn cần tuân thủ bản phát hành tệp kê khai v3 để có thể nhận được thông báo bất cứ khi nào một người tham gia tham gia cuộc gọi trên Meet.

2. Trước khi bắt đầu

Điều kiện tiên quyết

Mặc dù lớp học lập trình này phù hợp với người mới bắt đầu, nhưng việc nắm vững kiến thức cơ bản về JavaScript có thể giúp bạn có trải nghiệm tốt hơn nhiều.

Thiết lập/Yêu cầu

  • Trình duyệt Chrome
  • Thiết lập IDE/Trình chỉnh sửa trên hệ thống cục bộ.
  • Cài đặt gcloud cli nếu bạn muốn bật Gemini API bằng gcloud.

Bật 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. Bắt đầu chơi

Cài đặt tiện ích cơ bản

Hãy tạo một thư mục mà chúng ta sẽ sử dụng làm thư mục gốc của dự án.

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

Trước khi bắt đầu đặt câu hỏi cụ thể cho Gemini, hãy đặt một số câu hỏi về cấu trúc chung của tiện ích Chrome.

Lời nhắc:

What are the important parts to build a chrome extension?

Chúng ta nhận được một câu trả lời nêu rõ thông tin chi tiết nhỏ về tệp manifest, background script và thông tin chi tiết về giao diện người dùng. Hãy tìm hiểu thêm thông tin chi tiết về các tệp cụ thể này.

Lời nhắc:

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

Bạn có thể sử dụng tên mong muốn và email của mình trong trường tác giả.

Gemini trả về nội dung của tệp kê khai mà chúng ta cần, nhưng chúng ta nhận được một số trường bổ sung mà chúng ta không cần, chẳng hạn như trường action. Ngoài ra, chúng ta cần một nội dung mô tả. Hãy khắc phục vấn đề đó.

Lời nhắc:

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

Hãy đưa nội dung này vào tệp manifest.json trong thư mục gốc của dự án.

Ở giai đoạn này, tệp kê khai sẽ có dạng như sau.

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

Tạm thời xoá mọi trường bổ sung khác được tạo trong tệp kê khai vì lớp học lập trình này giả định các trường này trong tệp kê khai.

Vậy, làm cách nào để kiểm tra xem tiện ích có hoạt động hay không? Hãy hỏi bạn của chúng ta là Gemini nhé?

Lời nhắc:

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

Tiện ích này cung cấp cho tôi một số bước về cách kiểm tra. Hãy chuyển đến "Extensions Page" bằng cách chuyển đến chrome://extensions và nhớ bật nút "Developer Mode". Nút này sẽ hiển thị nút "Load unpacked". Chúng ta có thể sử dụng nút này để chuyển đến thư mục chứa các tệp tiện ích cục bộ. Sau khi thực hiện việc đó, chúng ta sẽ có thể thấy tiện ích trong "Extensions Page".

3d802a497ce0cfc2.png

92db1999a1800ecd.png

Tuyệt vời! Chúng ta có thể thấy tiện ích của mình, nhưng hãy bắt đầu thêm một số chức năng.

4. Thêm tập lệnh nội dung

Chúng ta chỉ muốn chạy một số mã JavaScript trên https://meet.google.com. Chúng ta có thể thực hiện việc này bằng cách sử dụng tập lệnh nội dung. Hãy hỏi Gemini cách thực hiện việc đó trong tiện ích của chúng ta.

Lời nhắc:

How to add a content script in our chrome extension?

Hoặc cụ thể hơn:

Lời nhắc:

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

Hoặc một phiên bản khác:

Lời nhắc:

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 cung cấp cho chúng ta những thay đổi chính xác mà chúng ta cần thực hiện trong tệp manifest.json và cả JavaScript mà chúng ta cần trong tệp content.js.

Khi thêm content_scripts, tệp kê khai của chúng ta sẽ trở thành:

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

Điều này cho biết Chrome sẽ chèn tập lệnh nội dung content.js bất cứ khi nào chúng ta chuyển đến một trang trong miền phụ " https://meet.google.com". Hãy thêm tệp này và kiểm tra nhé?

Hãy thêm mã này vào tệp content.js.

console.log("Hello Gemini");

Chắc chắn rồi! Khi truy cập vào meet.google.com, chúng ta sẽ thấy "Xin chào Gemini" trên bảng điều khiển 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

Tuyệt vời! Giờ đây, chúng ta có thể thêm một số chức năng cụ thể bằng JavaScript vào ứng dụng của mình. Hãy dành một chút thời gian để suy nghĩ về những gì chúng ta đang cố gắng đạt được.

Cải thiện tập lệnh nội dung

Chúng ta muốn có thể nhận được thông báo khi ai đó tham gia cuộc họp khi chúng ta đang ở trên trang cuộc họp(Nơi chúng ta có lựa chọn tham gia cuộc họp). Để đạt được điều này, hãy quan sát cách màn hình thay đổi trực quan khi cuộc họp trống so với khi có người tham gia cuộc họp.

Đây là giao diện khi không có ai trong cuộc họp.

fe5a0c95b20e7f72.png

Trong khi đó, đây là hình ảnh khi có một số người tham gia trong cuộc họp.

7a5ef60521d961cc.png

Chúng ta có thể thấy ngay 2 điểm khác biệt đáng chú ý:

  1. Văn bản trạng thái thay đổi từ "Không có ai khác ở đây" thành "[Người dùng] đang tham gia cuộc gọi này".
  2. Chúng ta có thể thấy hình ảnh của những người dùng đã tham gia cuộc gọi.

Cả hai thay đổi này đều sẽ hoạt động đối với chúng ta nếu chúng ta muốn biết có ai đã tham gia cuộc họp hay không, nhưng thay đổi sau có một số khả năng để lấy thông tin về những người dùng đã tham gia, vì vậy, hãy thử sử dụng thay đổi đó.

Mở "Trình kiểm tra phần tử" trong Chrome bằng phím nóng ( Mac: Cmd + Opt + C / Win: Ctrl + Shift + C) rồi nhấp vào hình ảnh của người dùng đã tham gia.

Chúng ta có thể nhận thấy rằng có một hình ảnh có một vài chuỗi lớp và thuộc tính tiêu đề của hình ảnh có tên của người dùng đã tham gia cuộc họp. Hơn nữa, thẻ hình ảnh này được gói trong một div có lớp U04fid. Sau khi thêm một số người tham gia vào cuộc họp thử nghiệm, chúng ta có thể thấy rằng div mẹ này lưu trữ nhiều hình ảnh(tương ứng với nhiều người dùng).

Vì vậy, chúng ta có một chiến lược một phần trong đầu:

  1. Phát hiện khi div có lớp U04fid chứa bất kỳ phần tử nào.
  2. Nếu có, thì điều đó có nghĩa là chúng ta có người tham gia trong cuộc họp.
  3. Thông báo cho người dùng.

Hãy quay lại Gemini và hỏi cách chúng ta có thể thực hiện việc này từng bước.

Lời nhắc:

How to detect for element changes in the HTML page?

Tiện ích này cung cấp cho chúng ta một giải pháp liên quan đến MutationObserver, nhưng không có gì cụ thể cho yêu cầu của chúng ta, hãy thử sửa đổi lời nhắc.

Lời nhắc:

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

Lần này, chúng ta nhận được một giải pháp không bao gồm MutationObserver nhưng là một giải pháp kiểm tra người tham gia bằng cách sử dụng div mẹ.

Đây là những gì chúng ta nhận được:

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

Hãy thử sửa đổi phương pháp của chúng ta hơn nữa:

Lời nhắc:

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.

Tiện ích này trả về đoạn mã sau:

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

Sao chép mã này vào tệp content.js, tải lại tiện ích(sau đó tải lại trang Meet).

Giờ đây, khi có người tham gia cuộc họp, chúng ta có thể thấy câu lệnh nhật ký trong bảng điều khiển.

5. Gửi thông báo cho người dùng

Giờ đây, khi có thể phát hiện thời điểm người tham gia đã tham gia cuộc họp, hãy thử thêm phần thông báo vào tiện ích Chrome. Chúng ta có thể duyệt xem tài liệu của tiện ích Chrome hoặc thậm chí điều chỉnh lời nhắc để biết những gì chúng ta đang tìm kiếm, nhưng về cơ bản, chúng ta cần sử dụng API chrome.notifications.create và lệnh gọi đến phương thức này phải là từ một trình chạy dịch vụ nền.

Lời nhắc:

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

Chúng ta thấy một số bước chi tiết với những điểm nổi bật chính là:

  • Thêm quyền notifications vào tệp kê khai.
  • Thực hiện lệnh gọi đến chrome.notifications.create
  • Lệnh gọi phải nằm trong tập lệnh nền.

Để thêm tập lệnh nền vào tiện ích Chrome trong manifest version 3, chúng ta cần khai báo background.service_worker trong tệp manifest.json.

Vì vậy, chúng ta tạo một tệp có tên là background.js và thêm nội dung sau vào tệp manifest.json.

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

Khi thêm các nội dung trên, tệp kê khai của chúng ta sẽ trở thành:

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

Lời nhắc:

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

Lưu hình ảnh này vào thư mục gốc của bạn và đổi tên thành success.png.

b2c22f064a3f2d9c.png

Sau đó, hãy thêm đoạn mã sau vào 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");

Bây giờ, hãy tải lại tiện ích từ trang tiện ích và bạn sẽ thấy ngay một cửa sổ bật lên thông báo.

6. Thêm tính năng truyền thông báo vào tiện ích Chrome

Giờ đây, bước chính cuối cùng mà chúng ta cần là kết nối tính năng phát hiện người tham gia của tập lệnh nội dung và phương thức sendNotification trong tập lệnh nền. Trong bối cảnh tiện ích Chrome, cách thực hiện việc đó là thông qua một kỹ thuật có tên là message passing.

Điều này cho phép giao tiếp giữa các phần khác nhau của tiện ích của Chrome, trong trường hợp của chúng ta là từ tập lệnh nội dung đến trình chạy dịch vụ nền. Hãy hỏi bạn của chúng ta là Gemini cách thực hiện việc đó.

Lời nhắc:

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

Gemini phản hồi bằng các lệnh gọi có liên quan đến chrome.runtime.sendMessagechrome.runtime.onMessage.addListener.

Về cơ bản, chúng ta sẽ sử dụng sendMessage để gửi thông báo từ tập lệnh nội dung rằng ai đó đã tham gia cuộc gọi trên Meet và onMessage.addListener làm trình nghe sự kiện để phản hồi thông báo do tập lệnh nội dung gửi. Trong trường hợp này, chúng ta sẽ kích hoạt lệnh gọi đến phương thức sendNotification từ trình nghe sự kiện này.

Chúng ta sẽ truyền thông báo và thuộc tính action đến trình chạy dịch vụ nền. Thuộc tính action mô tả nội dung mà tập lệnh nền đang phản hồi.

Vì vậy, đây là mã content.js của chúng ta:

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

Và đây là mã background.js của chúng ta:

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

Hãy thử tuỳ chỉnh thông báo và nhận mã thông báo duy nhất. Đối với thông báo, chúng ta có thể thêm tên của người dùng. Nếu nhớ lại một bước trước đó, chúng ta có thể thấy tên của người dùng trong thuộc tính tiêu đề của hình ảnh. Vì vậy, chúng ta có thể tìm nạp tên của người tham gia bằng cách sử dụng document.querySelector('div.U04fid > img').getAttribute('title').

Về mã thông báo, chúng ta có thể tìm nạp mã thẻ của tập lệnh nội dung và sử dụng mã đó làm mã thông báo. Bạn có thể thực hiện việc này bên trong trình nghe sự kiện chrome.runtime.onMessage.addListener bằng cách sử dụng sender.tab.id.

Cuối cùng, các tệp của chúng ta sẽ có dạng như sau:

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. Xin chúc mừng

Trong một thời gian ngắn, chúng ta đã có thể xây dựng một tiện ích của Chrome với sự trợ giúp của Gemini. Dù bạn là nhà phát triển tiện ích Chrome có kinh nghiệm hay mới làm quen với thế giới tiện ích, Gemini đều có thể giúp bạn thực hiện bất kỳ nhiệm vụ nào bạn muốn.

Tôi khuyến khích bạn hỏi về những việc khác nhau mà bạn có thể làm với tiện ích Chrome. Có nhiều API đáng để duyệt xem, chẳng hạn như chrome.storage, alarms, v.v. Bất cứ khi nào bạn cảm thấy bế tắc, hãy sử dụng Gemini hoặc tài liệu để biết bạn đang làm sai điều gì hoặc để thu thập các cách giải quyết vấn đề.

Bạn thường phải sửa đổi lời nhắc để nhận được sự trợ giúp cần thiết, nhưng chúng ta có thể thực hiện việc này từ một thẻ giữ lại tất cả hành trình theo ngữ cảnh của chúng ta.