浏览器扩展:在 browser-action-popup 和 background-script 之间发送消息(带响应)

Browser extensions: Send messages (with response) between browser-action-popup and background-script

首先,我不是在寻找长期连接。我正在专门寻找一种发送消息并发送对这些消息的直接响应的方法。

当您在内容脚本和背景脚本之间发送消息时,它非常简单,因为您使用 chrome.tabs API 到 send/receive 消息 from/to内容脚本。并且要 send/receive 消息 from/to 您使用 chrome.runtime API 的后台脚本。

但是浏览器操作弹出窗口有点不同,因为两者都 运行 在背景上下文中。所以我想他们都必须使用 chrome.runtime API。

但这意味着我必须在我的浏览器操作弹出窗口和后台脚本中收听 chrome.runtime.onMessage。所以基本上我会在后台脚本中收到从弹出窗口发送的消息,也会在弹出窗口本身中收到消息。反之亦然。

所以是的,这真的行不通:

/////////////background-script//////////////
//Send message from background-script to browser-action-popup
chrome.runtime.sendMessage({msg:"This is a message sent from the background-script to the browser-action-popup"})
  .then(response => { //Receive response from the browser-action-popup
      console.log(response.msg)
  })

//Receive messages from browser-action-popup
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse) {
    sendResponse({msg:"This is a response message sent from the background-script"})
    return true
})

...

///////////browser-action-popup/////////////
//Send message from browser-action-popup to background-script
chrome.runtime.sendMessage({msg:"This is a message sent from the browser-action-popup to the background-script"})
  .then(response => { //Receive response from the background-script
      console.log(response.msg)
  })

//Receive message from background-script
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse) {
    sendResponse({msg:"This is a response message sent from the browser-action-popup"})
    return true
})

但由于它们都 运行 在后台上下文中,我也想知道是否没有比发送消息更简单的方法:是否可以在两者之间共享变量或者它们 运行宁完全隔离?

这很简单,只需为您的邮件指定一个类型或类似的某种邮件标识符即可。我在这个例子中称它为类型。

/////////////background-script//////////////
//Send message from background-script to browser-action-popup
var msg = {
    data : "This is a message sent from the background-script to the browser-action-popup",
    type : "notifyPopupOfMessage"
};

chrome.runtime.sendMessage(msg)
.then(response =  > { //Receive response from the browser-action-popup
        console.log(response.data);
    })

//Receive messages from browser-action-popup
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    if (message.type === 'notifyBackgroundOfMessage') {
        var msg = {
            data : "This is a response message sent from the background-script",
            type: 'notifyPopupOfMessage'
        };

        sendResponse(msg);
    }

    return true
});

.....

///////////browser-action-popup/////////////
//Send message from browser-action-popup to background-script

var msg = {
    data: 'This is a message sent from the browser-action-popup to the background-script',
    type: 'notifyBackgroundOfMessage'
};

chrome.runtime.sendMessage(msg)
  .then(response => { //Receive response from the background-script
      console.log(response.data);
  });

//Receive message from background-script
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse) {
    if(message.type === 'notifyPopupOfMessage') {
        var msg = {
            data:"This is a response message sent from the browser-action-popup",
            type: 'notifyBackgroundOfMessage'
        };
        sendResponse(msg);
    }

    return true
});

希望对您有所帮助。

来自the docs

If sending to your extension, the runtime.onMessage event will be fired in every frame of your extension (except for the sender's frame)

因此您不必担心来自弹出窗口的消息会触发弹出窗口上的 onMessage 事件。

您还要求通过共享变量来实现另一种通信方式。从弹出窗口中,您可以使用 {type: 'popup'} 调用 chrome.runtime.getBackgroundPage, that to get the JavaScript window object for the background page. And from the background page you can call chrome.extension.getViews 以访问弹出窗口的 window 对象(如果它已打开)。

getBackgroundPageFirefox documentation 状态:

This provides a convenient way for other privileged add-on scripts to get direct access to the background script's scope. This enables them to access variables or call functions defined in that scope. "Privileged script" here includes scripts running in options pages, or scripts running in browser action or page action popups, but does not include content scripts.

虽然 Daniel Lane 的回答在理论上可行,但我不喜欢使用 msg 对象来识别发件人。我实际上找到了一种巧妙的方法来过滤掉从同一个 "page"(backgorund、popup 等)发送的消息。
我通过识别当前页面 url 并将其与 sender.url 进行比较来完成它。这是我的全部代码:

popup.js

const THIS_PAGE_URL = chrome.runtime.getURL('popup.html')

//Send message from browser-action-popup to background-script
setTimeout(function(){

    chrome.runtime.sendMessage({msg:"This is a message sent from the browser-action-popup to the background-script"})
      .then(response => { //Receive response from the background-script
          if (!response) {
              console.log("Popup sent a msg and received no response.")
              return
          }
          document.body.innerHTML += "<br>Popup sent a msg and received a response: " + response.msg
      })

}, 3000)


//Receive message from background-script
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse) {
    if (sender.url === THIS_PAGE_URL)
        return
    document.body.innerHTML += "<br>Popup received a new msg: " + message.msg
    sendResponse({msg:"This is a response message sent from the browser-action-popup"})
    return true
})

background-script.js

const THIS_PAGE_URL = chrome.runtime.getURL('_generated_background_page.html')

//Send message from background-script to browser-action-popup
setTimeout(function(){

    chrome.runtime.sendMessage({msg:"This is a message sent from the background-script to the browser-action-popup"})
      .then(response => { //Receive response from the browser-action-popup
          if (!response) {
              console.log("Background-script sent a msg and received no response.")
              return
          }
          console.log("Background-script sent a msg and received a response: " + response.msg)
      })

},3000)


//Receive messages from browser-action-popup
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse) {
    if (sender.url === THIS_PAGE_URL)
        return
    console.log("Background-script received a new msg: " + message.msg)
    sendResponse({msg:"This is a response message sent from the background-script"})
    return true
})

对于那些感兴趣的人,这里是剩余的文件:

popup.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <script src="popup.js"></script>
  </body>
</html>

manifest.json

{
  "manifest_version": 2,
  "name": "popup-background-msg-example",
  "version": "1.0",

  "browser_action": {
    "browser_style": true,
    "default_title": "popup-background-msg-example",
    "default_popup": "popup.html"
  },

  "background": {
    "scripts": ["background-script.js"]
  }
}