iT邦幫忙

2021 iThome 鐵人賽

DAY 4
0
自我挑戰組

只不過是想強迫自己定時喝個水有必要那麼麻煩嗎之我想寫一個 Chrome Extension 強迫我喝水系列 第 4

[拯救上班族的 Chrome 擴充套件] Chrome Extention 的訊息傳接球

Hi 各位大大~
今天要來分享在 Chrome extension 訊息傳遞的部分,
主要算是官方文件的導讀,
我們為什麼需要傳遞訊息?

官方文件:Since content scripts run in the context of a web page and not the extension, they often need some way of communicating with the rest of the extension.

簡單來說就是網頁的內容已經不是擴充的一部分,
但他們又很常需要跟擴充去溝通,
基本上有三種用法,但是今天只主要會講前兩個
(第三個我目前沒需求使用到)

  1. one-time requests
    如果你只需要傳送單一的訊息,可以用兩種方式,一個是 runtime.sendMessage , 另一個則是 tabs.sendMessage,它可以讓你傳 JSON 格式的訊息 , 然後有一個 callback 參數是 option 的,如果你希望他的 response 是你需要 handle 的話可以用這個。
    如果你想從 content script 傳送 request 出來可以使用像是以下範例的做法。

    chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
      console.log(response.farewell);
    });
    

    如果你想從 extension 傳送到 content script 可以透過以下做法。

    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
      chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
        console.log(response.farewell);
      });
    });
    

    基本上可以把它拆成兩段,第一段是去搜尋目前 tab 的ID ,將第一個拿到的 ID 作為指定的目標,當然你也可以自己把它改成寄送所有頁面可參考以下範例。

    chrome.tabs.query({}, function(tabs) {
        const message = {foo: bar};
        for (let i=0; i < tabs.length; ++i) {
            chrome.tabs.sendMessage(tabs[i].id, message);
        }
    });
    

    最後,有傳送當然就有接收,你可以在content script 或是 extension 藉由以下範例去接收傳送的訊息,如下面範例

    chrome.runtime.onMessage.addListener(
      function(request, sender, sendResponse) {
        console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
        if (request.greeting === "hello")
          sendResponse({farewell: "goodbye"});
      }
    );
    

    官方提醒:Note:

    1. If multiple pages are listening for onMessage events, only the first to call sendResponse() for a particular event will succeed in sending the response. All other responses to that event will be ignored.
    2. The sendResponse callback is only valid if used synchronously, or if the event handler returns true to indicate that it will respond asynchronously. The sendMessage function's callback will be invoked automatically if no handlers return true or if the sendResponse callback is garbage-collected.

    翻譯蒟蒻:

    1. 如果有多個頁面在監聽 onMessage 的 events sendResponse() 只有第一個成功送出回應的會被理,其他都會被忽略QQ
    2. 如果 sendResponse 要被使用非同步的話要在最後 return true ,否則他就只允許你讓他被同步的使用。
  2. long-lived connections
    如果你需要較長時間的請求的話可以用這個方式,一樣有兩種用法,一個是 runtime.connect 另一個則是 tabs.connect ,另外他有可以讓你選擇該 channel 的名稱,讓你去區分不同的連線。
    如果是 content script 你可以參考如以下範例,

    const port = chrome.runtime.connect({name: "knockknock"});
    port.postMessage({joke: "Knock knock"});
    port.onMessage.addListener(function(msg) {
      if (msg.question === "Who's there?")
        port.postMessage({answer: "Madame"});
      else if (msg.question === "Madame who?")
        port.postMessage({answer: "Madame... Bovary"});
    });
    

    如果是 extension 的部分其實非常相似如以下範例,

    chrome.runtime.onConnect.addListener(function(port) {
      console.assert(port.name === "knockknock");
      port.onMessage.addListener(function(msg) {
        if (msg.joke === "Knock knock")
          port.postMessage({question: "Who's there?"});
        else if (msg.answer === "Madame")
          port.postMessage({question: "Madame who?"});
        else if (msg.answer === "Madame... Bovary")
          port.postMessage({question: "I don't get it."});
      });
    });
    

以上是今天的內容,
從這邊你就可以想像,

今天你透過擴充讓使用者在設定一些東西時,想要讓畫面做一些什麼事情,
比方說充滿貓咪,然後異常抖動或是縮放,基本上就是

擴充: 欸欸 插入圖片
Content script : 收到! 我插入了... 圖片! 阿斯~
擴充: 欸欸 他喝水了
Content script : 收到! 我把插入的... 圖片取消了~

以上是今天分享的內容
祝各位連假快樂xD

感謝各位,我們明日再戰。

參考文獻:

Message passing


上一篇
[拯救上班族的 Chrome 擴充套件] 規劃架構和使用情境
下一篇
[拯救上班族的 Chrome 擴充套件] 你渴望貓咪嗎?那就把貓咪插入到每個頁面吧!
系列文
只不過是想強迫自己定時喝個水有必要那麼麻煩嗎之我想寫一個 Chrome Extension 強迫我喝水6

尚未有邦友留言

立即登入留言