Reputation: 6554
bacground.js
chrome.tabs.create({url: "http://www.google.com", "active":true}, function(tab) {
console.log(tab.id);// 315
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
contentscript.js
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"});
});
});
logs:
Port: Could not establish connection. Receiving end does not exist.
How to fix it?
Upvotes: 2
Views: 193
Reputation: 558
This error seems to be happening because the content script has not yet been injected into the page when your background script sends the message. Hence, the "receiving end does not exist."
I'm assuming (because I don't have more than 50 rep to be able to comment on your question and clarify this first, so correct me if I am wrong) that in your manifest.json file, you specify it in the following way:
"content_scripts": [{
"matches": ["*://xyz.com/*"],
"js": ["contentscript.js"]
}]
If this is indeed how you are injecting the content script, then you need to know that the content script only gets injected after the DOM has finished rendering. (Search for 'run_at' on the following link: http://developer.chrome.com/extensions/content_scripts.html) This means that when you send that message from the background script, the content script is still "loading."
The good news is that you can specify when the content script should be loaded by adding a third key-value pair to the content_scripts parameter in the manifest.json file, like so:
"content_scripts": [{
"matches": ["*://xyz.com/*"],
"js": ["contentscript.js"],
"run_at": "document_start"
}]
This tells the extension that you want to inject the contentscript.js before the DOM is constructed or any other script is run (i.e. as early as possible).
If the above technique still gives you the same error, that's an indication that even document_start is not early enough. In that case, let's consider another approach entirely. What you are attempting to do presently is to have the background script connect to the content script. Why not have the content script connect to the background script instead when it has successfully been injected into the page? The background page is always running so it is guaranteed to be able to receive the message from the content script without complaining about "the receiving end does not exist." Here is how you would do it:
In background.js:
chrome.runtime.onConnect.addListener(function(port) {
console.log("background: received connection request from
content script on port " + port);
port.onMessage.addListener(function(msg) {
console.log("background: received message '" + msg.action + "'");
switch (msg.action) {
case 'init':
console.log("background script received init request
from content script");
port.postMessage({action: msg.action});
break;
}
});
});
In contentscript.js:
var port_to_bg = chrome.runtime.connect({name: "content_to_bg"});
port_to_bg.postMessage({action: 'init'});
port_to_bg.onMessage.addListener(function(msg) {
switch (msg.action) {
case 'init':
console.log("connection established with background page!");
break;
}
}
Feel free to ask more questions for clarification! I'd be curious to learn if the first approach worked. If not, the second approach is a sure win.
Upvotes: 3