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 pletely isolated?
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 pletely isolated?
Share Improve this question edited Jan 28, 2017 at 18:46 Forivin asked Jan 27, 2017 at 13:55 ForivinForivin 15.6k30 gold badges118 silver badges212 bronze badges 6- 1 Possible duplicate of Communicate between scripts in the background context (background script, browser action, page action, options page, etc.) – Makyen ♦ Commented Jan 27, 2017 at 18:13
-
There is a bug in (now older versions of) Firefox that results in
runtime.sendMessage()
is triggering its ownruntime.onMessage
listener. This bug exists in Firefox 50.1.0 (now old). In my testing, this does not happen in Firefox 51.0.1 (now the current release version of Firefox). – Makyen ♦ Commented Jan 27, 2017 at 18:35 -
FYI: I have updated the
runtime.onMessage
to include a note regarding this bug and the fact that it can result in locking up Firefox (if you unconditionally callruntime.sendMessage()
from within aruntime.onMessage
listener). You may need to reload the page using Ctrl-F5 to see the change. – Makyen ♦ Commented Jan 27, 2017 at 19:06 -
How is this not a duplicate of the proposed dup-target? You claim that it is because you are "not looking for Long Lived Connections", but that question/answer only mentions
connect
/onConnect
as one of the various methods of municating, and mostly concentrated on the multiple other methods using exactly the same methods described in this question/answer (sendMessage()
/onMessage
). In other words, that question/answer is a superset of what you are asking here. It covers all the methods of municating in the background context, not the limited subset discussed here. – Makyen ♦ Commented Jan 28, 2017 at 16:19 - 1 Possible duplicate of Communicate between scripts in the background context (background script, browser action, page action, options page, etc.) – Forivin Commented Jan 28, 2017 at 18:46
3 Answers
Reset to default 2From 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 munication 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.
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.
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 paring 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"]
}
}