chrome extension contentscript not receiving messages from background script long life connection - google-chrome-extension

I'm having a frustrating problem with message handling in Chrome,
I have a long lived connection running across my background page and popup page, the content page is able to send messages but not receive.
I've tired a number of methods but no joy.
Has anyone else encountered this?
content.js
coms = chrome.extension.connect({name: "coms"});
coms.onMessage.addListener(function(data) {
console.log("com chatter");
});
popup.js
coms = chrome.extension.connect({name: "coms"});
chrome.extension.onConnect.addListener(function(port) {
console.assert(port.name == "coms");
port.onMessage.addListener(function(msg) {
console.log("com chatter");
});
});

Related

why the active tabs was undefined when send message from backend to content script in google chrome extension v3

I am tried to send message from background in google chrome extension v3, this is the background message send code looks like:
export function sendMessageToContent(message: MessageBase) {
debugger
chrome.tabs.query({active:true,currentWindow:true},function(tabs){
var activeTab = tabs[0];
if(activeTab && activeTab.id !== undefined){
chrome.tabs.sendMessage(activeTab.id, {"message": "clicked_browser_action"});
}
});
}
when I get the current active tab, the tabs was return undefined, why did this happen? I am sure there contains active tabs in google chrome broswer, what should I do to fix this problem? This is the debug view:

Communicating between two chrome extensions

I am trying to communicate between two chrome extensions, but unable to do so.
Any help would be great in resolving this issue.
1st extension sending msg in background.js:
chrome.browserAction.onClicked.addListener(
function(tab)
{
chrome.runtime.onConnect.addListener(function(port)
{
port.postMessage({status:"hello"});
});
2nd extension receiving msg in background.js:
var port = chrome.runtime.connect({name: "lkddmaimhocofkfhngkdhdicmldnfdpn"});
port.onMessage.addListener(function(message,sender)
{
alert('listened bg');
});
It seems you are confused with the sending part and receiving part.
Also, there are some differences between onConnect
which fires when a connection is made from either an extension process or a content script,
and onConnectExternal
which fires when a connection is made from another extension.
Take a look at Message External and you can use the following sample code to communicate between two extensions.
1st extension sending msg in background.js:
chrome.browserAction.onClicked.addListener(function() {
var port = chrome.runtime.connect("lkddmaimhocofkfhngkdhdicmldnfdpn");
port.postMessage(...);
});
2nd extension receiving msg in background.js:
chrome.runtime.onConnectExternal.addListener(function(port) {
port.onMessage.addListener(function(msg) {
// Handle your msg
});
});

Firefox Extension Development

In Chrome Extension Development we have Background Page Concepts. Is any thing similar available in Firefox Extension Development also. While Developing Chrome Extensions I have seen methods like
window.Bkg = chrome.extension.getBackgroundPage().Bkg;
$(function () {
var view = null;
if (Bkg.account.isLoggedIn()) {
view = new Views.Popup();
$("#content").append(view.render().el);
} else {
$("#content").append(Template('logged_out')());
Bkg.refresh();
}
}...........
Where the main logic are written in Background Page(like isLoggedIn etc) and from the Extension Popup page we are calling Background page. Here for instance the background page is always loaded which manages the session. How can we have similar functionality in Firefox Extension Development.
All communication between the background page (main.js) and content scripts (your popup script) occurs via events. You cannot call functions immediately, so you won't receive any return values, but you can send an event from a content script to the background script that sends an event back to the content script and calls a new function, like so:
main.js partial
// See docs below on how to create a panel/popup
panel.port.on('loggedIn', function(message) {
panel.port.emit('isLoggedIn', someBoolean);
});
panel.port.on('refresh', function() {
// do something to refresh the view
});
popup.js
var view = null;
addon.port.on('isLoggedIn', function(someBool) {
if (someBool) {
// Obviously not code that's going to work in FF, just want you to know how to structure
view = new Views.Popup();
$("#content").append(view.render().el);
} else {
$("#content").append(Template('logged_out')());
addon.port.emit('refresh');
}
});
addon.port.emit('loggedIn', 'This is a message. I can pass any var along with the event, but I don't have to');
You should read this stuff:
Panel
Communicating between scripts

chrome extension messaging from background to content script gives :Port error: Could not establish connection. Receiving end does not exist [duplicate]

For my Chrome extension, I am attempting to post selected text to a PHP webpage. A solved question on this website (Chrome Extension: how to capture selected text and send to a web service) has helped me a lot in achieving this, but I want a different way of posting the text.
Instead of XMLHttpRequest as mentioned there, I want to send a hidden JS form from the content script. This method allows me to view or change the text before importing it to the database.
The problem is to get the trigger from the background to the content script. I already have a message the other way, so using the function(response) is desired. However, outside the “sendMessage”, I can’t listen for the response.cmd. And inside the “sendMessage”, I can’t get the response.cmd to trigger a function. Is there a solution for this, other than sending an all new message from the background script?
The code I am referring to:
Background.js
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if(request.cmd == "createSelectionMenu") {
sendResponse({cmd: "saveText"}); //Do things
}
});
Content_script.js
chrome.extension.sendMessage({ cmd: "createSelectionMenu", data: selectedText },
function(response) {
if(response.cmd == "saveText") {
createForm();
}
}
});
What I do is following:
I keep track of my opened tabs
content script:
// connect to the background script
var port = chrome.extension.connect();
background script
// a tab requests connection to the background script
chrome.extension.onConnect.addListener(function(port) {
var tabId = port.sender.tab.id;
console.log('Received request from content script', port);
// add tab when opened
if (channelTabs.indexOf(tabId) == -1) {
channelTabs.push(tabId);
}
// remove when closed/directed to another url
port.onDisconnect.addListener(function() {
channelTabs.splice(channelTabs.indexOf(tabId), 1);
});
});
Now I can notify all my registered tabs (i.e. content scripts) from my background script when a certain action happened:
var notification = { foo: 'bar' };
for(var i = 0, len = channelTabs.length; i < len; i++) {
chrome.tabs.sendMessage(channelTabs[i], notification, function(responseMessage) {
// message coming back from content script
console.log(responseMessage);
});
}
And again, on the other side in the content script, you can add a listener on these messages:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if (request.foo == 'bar') {
executeStuff();
// if a callback is given:
sendResponse && sendResponse('success');
}
});
It's a bit of a brainf*ck, because it's redundant at some places. But I like it best that way, because you can wrap it and make it a bit easier.
If you want to see how I am using this, see my repository on GitHub: chrome-extension-communicator.

Background to content-script of preloading page message fails

Something strange happens in the Chrome extension.
Content script:
console.log('content');
chrome.extension.onRequest.addListener(function(request, sender, sendResponse){
console.log('request received');
sendResponse();
});
chrome.extension.sendRequest( JSON.stringify({'msg': 'page_loaded'}) );
It is just listens for extension messaging and sends the message to the background when page loaded.
Background script:
console.log('bg');
chrome.extension.onRequest.addListener(function(request, sender, sendResponse){
sendResponse();
chrome.tabs.sendRequest(
sender.tab.id,
JSON.stringify({'msg': 'page_loaded_bg_receive'}),
function(){
console.log('sendRequest page_loaded_bg_receive callback');
});
});
It is listens for messages and sends message to the sender tab.
And it seems to be working, at least in most cases in the page log appears 'request received'.
While url entering Chrome sometimes loads typed address before user hits 'enter'. And that's a strange behavior: page loading, content-script runs, sends the message to the background, but when the background sends the message back — it fails with the background log message:
Port error: Could not establish connection. Receiving end does not exist. miscellaneous_bindings:184
chromeHidden.Port.dispatchOnDisconnect miscellaneous_bindings:184
Is this a Chrome bug? What to do to send message to the preloading tab?
This is the arfificial minimal sample to reproduce such behavior. I need to call 'chrome.tabs.sendRequest' after the handling the message and more than once, so calling the 'sendResponse' is not the solution.
Solution based on the article https://developers.google.com/chrome/whitepapers/pagevisibility. I run content-script code if document.webkitVisibilityState is not 'hidden' or 'prerender', elsewhere I listen for 'webkitvisibilitychange' and wait for document.webkitVisibilityState is not 'hidden' or 'prerender'. I think check for 'prerender' is enough, but when I open a new empty tab it loads page with document.webkitVisibilityState='hidden' and this page also did not receive background messages.
function isDocumentReady() {
return document.webkitVisibilityState != "hidden" && document.webkitVisibilityState != "prerender";
}
if (isDocumentReady())
main();
else {
function onVisibilityChange() {
if (!isDocumentReady())
return;
document.removeEventListener(
"webkitvisibilitychange",
onVisibilityChange,
false);
main();
}
document.addEventListener(
"webkitvisibilitychange",
onVisibilityChange,
false);
}

Resources