Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

First of all I'm not looking for Long Lived Connections. I'm specifically looking for a way to send messages and send direct responses to these messages.

When you send messages between a content-script and a background-script it's pretty straight forward, as you use the chrome.tabs API to send/receive messages from/to the content-script. And to send/receive messages from/to the background-script you use the chrome.runtime API.

But with browser-action-popups it is a bit different because both are running in a background-context. So I suppose they both have to use the chrome.runtime API.

But that would mean I'd have to listen to chrome.runtime.onMessage in both my browser-action-popup and in my background-script. So basically I would receive message sent from the popup in the background-script, but also in the popup itself. And the other way around it would be the same.

So yeah, this wouldn't really work:

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

But since they both run in a background context I was also wondering is there isn't a simpler way than sending messages: Would it be possible to share variables between the two or are they running completely isolated?

like image 684
Forivin Avatar asked Jan 27 '17 13:01

Forivin


People also ask

How do you send a message from the background script to pop up?

tabs. sendMessage( tab.id, youtPayload, function (response) { // do something here if you want } ); }); }); That's it!

How do you communicate between content script and popup?

The popup can contain any HTML contents that you like, and it's automatically sized to fit its contents. To add a popup to your browser action, create an HTML file with the popup's contents. Specify the HTML file in the default_popup field of browser_action in the manifest, or call the browserAction.

How do I send a message to content script?

To send a message to a content script, use chrome. tabs. sendMessage and specify the TabId . The message will be sent to the content script running in that tab.

How do I open a pop up extension in Chrome?

Open-as-Popup. Opens the current tab as a popup window. This extension is very simple: it provides a button to open the current tab as a popup window. The tab will be closed, and a popup window - that is, a window without tabs or a URL bar - will be opened to the same address.


3 Answers

From 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)

So you don't have to worry for a message from the popup triggering the onMessage event on the popup.

You also ask for another mean of communication by sharing variables. From the popup you can call 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 with {type: 'popup'} to access the window object for the popup, if it is open.

The Firefox documentation for getBackgroundPage states:

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.

like image 199
rsanchez Avatar answered Oct 29 '22 23:10

rsanchez


This is an easy one, just give your messages a type or similar, some kind of message identifier. I've called it type in this example.

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

Hope that helps.

like image 23
Daniel Lane Avatar answered Oct 30 '22 00:10

Daniel Lane


Although Daniel Lane's answer would theoretically work, I'm not a fan of using the msg object to identify the sender. I actually found a neat way to filter out messages sent from the same "page" (backgorund, popup, etc).
I've done it by identifying the current page url and comparing it to the sender.url . Here is my whole code:

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

And for those who are interested here are the remaining files:

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"]
  }
}
like image 38
Forivin Avatar answered Oct 30 '22 01:10

Forivin