I am getting a trouble about passing message inside background page of chrome extension.
In content page
I send a message and wait for a response from background page:
chrome.runtime.sendMessage({"name": "Calling"}, function (response) {
console.log(response);
});
In background page
I have an event listener to listen message from content page:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.name == "Calling") {
doTask().then(function (message) {
sendResponse(message);
});
return true; // Make respond asynchronously
}
}
);
Inside "Calling" event Listener, i call the function doTask() which return a promise:
var doTask = function(){
return new Promise(function (resolve) {
chrome.runtime.sendMessage({"name": "DoTask"}, function (response) {
resolve(response);
});
});
};
Inside doTask() i send another message "DoTask", and wait for response.
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.name == "DoTask") {
var message = "Task has done!";
sendResponse(message);
return true; // Make respond asynchronously
}
}
);
I expect "Task has done!" will be printed in content page, but nothing appears! When debugging i realize "DoTask" event listener cannot receive any message.
What wrong here? Thank you.
P/S: I make sure that all scripts are injected in manifest.json
Related
I'm trying to set a badge text specific for each tab in Chrome.
I've followed along with this answer https://stackoverflow.com/a/32168534/8126260 to do so, though the chrome.runtime.onMessage event handler is never being fired.
// tab specific badges https://stackoverflow.com/questions/32168449/how-can-i-get-different-badge-value-for-every-tab-on-chrome
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
console.log('runtime message');
if (message.badgeText) {
console.log('runtime message with badge text');
chrome.tabs.get(sender.tab.id, function(tab) {
if (chrome.runtime.lastError) {
return; // the prerendered tab has been nuked, happens in omnibox search
}
if (tab.index >= 0) { // tab is visible
chrome.browserAction.setBadgeText({tabId:tab.id, text:message.badgeText});
console.log('set message');
} else { // prerendered tab, invisible yet, happens quite rarely
var tabId = sender.tab.id, text = message.badgeText;
chrome.webNavigation.onCommitted.addListener(function update(details) {
if (details.tabId == tabId) {
chrome.browserAction.setBadgeText({tabId: tabId, text: text});
chrome.webNavigation.onCommitted.removeListener(update);
}
});
}
});
}
});
// block outgoing requests for help widgets
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
//send message
console.log('send message');
chrome.runtime.sendMessage({badgeText: "HELP"});
if (isDisabled) {
return { cancel: false } // this should return from the function (details) level
} else {
return { cancel: true }
}
},
{urls: [
"a bunch of urls irrelevant to this question"
]},
["blocking"]);
(the entire source code is on https://github.com/bcye/Hello-Goodbye)
Looking into the console of my background script, send message appears, meaning that chrome.runtime.sendMessage({badgeText: "HELP"}); should have been executed.
None of the console.log statements in the onMessage listener get executed though.
Solved it, as #wOxxOm said this is impossible.
Though webRequest passes a tabId in the details dictionary.
This can be used to replicate that.
I am trying to send a message from a content script to my background script. When the background receives the message it sends data back to the content script in the callback.
My popup also has a listener for messages from the content script, but does not respond to a message meant for the background script.
Then content is receiving an undefined back from the callback, which I think is caused by the popup receiving the message but not responding.
The reference says:
Note: If multiple pages are listening for onMessage events, only the
first to call sendResponse() for a particular event will succeed in
sending the response. All other responses to that event will be
ignored.
So surely I should only get the response from my background script.
My content script does this:
function notifyReady() {
chrome.runtime.sendMessage({
type: 'ACTIVITY_HISTORY_READY'
},
function (response) {
console.log(">>>>Response: ", response);
if (response.type == 'HISTORY_DATA') {
processLog(response);
}
});
}
My background script listens like this:
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
console.log("received " + msg.type);
if (msg.type = 'ACTIVITY_HISTORY_READY' && historyData) {
if (historyData) {
sendResponse({
type: "HISTORY_DATA",
position: historyData.position,
company: historyData.company
});
historyData = '';
} else {
sendResponse({
type: "NO_DATA"
});
}
}
});
And the listener in my popup is:
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg.type == 'JOB_DETAILS') {
sendResponse("OK!");
document.getElementById('position').value = msg.position;
document.getElementById('company').value = msg.company;
document.getElementById('url').value = sender.tab.url;
}
});
if (msg.type = 'ACTIVITY_HISTORY_READY' && historyData) {
note that if historyData is falsey you are not sending any response. The else branch of the second if can never be taken.
You should remove historyData from the first if. The popup code has nothing to do with this.
I'm trying to get some user configs from the background page of my chrome extension to the content script (or popup) but I'm having some problems, I think the problem is that chrome.storage.sync.get is async, I tried using callbacks but I also read that callbacks can't return the value so I have no idea how to solve this.
Here's kinda how the code looks:
popup.js:
(function() {
chrome.runtime.sendMessage({
message: "loadconfig"
}, function(response) {
console.log(response);
if (response.status === 'success') {
console.log(response);
} else {
console.log(response.except);
}
});
})();
background.js
(function() {
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
switch (request.message) {
case "loadconfig":
sendResponse(loadStuff());
break;
default:
sendResponse({
reply: null
});
break;
}
});
function loadStuff() {
var to_return_configs = {
blocked_characters: '',
good_post: ''
};
var function_status = 'failed';
var exception = '';
var blocked_characters_parsed, good_post_parsed;
try {
var to_get = ["blocked_characters_saved", "good_post_saved"];
chrome.storage.sync.get(to_get, function(result) {
to_get.forEach(function(got) {
if (got === "good_post_saved") {
to_return_configs.good_post = result[got];
}
if (got === "blocked_characters_saved") {
to_return_configs.blocked_characters = result[got];
}
});
});
exception = '';
function_status = 'success';
} catch (err) {
exception = String(err);
function_status = 'failed';
}
var to_return = {
status: function_status,
configs: to_return_configs,
except: (exception)
};
return to_return;
}
})();
The problem here is that when I'm looking at the popup.js console, "blocked_characters" and "good_post" are both empty.
How can I solve this?
You do not need Message API for communication between Popup and Background. Popup in chrome extension can directly call methods of Background .
You can do something like this
BG = chrome.extension.getBackgroundPage();
And then you can call BG.loadStuff() in your popup js.
From within loadStuff, you can pass a callback which can return data to you. So it should look like
BG.loadStuff(function(items) {
console.log(items);
});
background.js
function loadStuff(cb) {
chrome.storage.sync.get(null, function(superObj) {
cb.call(null, superObj);
});
}
For more understanding, read these
http://blog.papersapp.com/chrome-development-parent-and-child-windows/
https://stackoverflow.com/a/17276475/816213
https://stackoverflow.com/a/17378016/816213
sendResponse(function) becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called). See the reference: onMessage.
Because sendResponse is called asynchronously in chrome.storage.sync.get's callback, you need to return true from the onMessage listener to prevent the function from being invalidated. Code similar is Like:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === 'loadconfig') {
sendResponse(loadStuff());
return true;
}
return false;
});
I'm trying to build a chrome extension that involve sending request for data from popup script to Content script (through background script) analyze the request on the content script side and send back a response (again through the background script).
The popup script code:
chrome.runtime.sendMessage({action:"getLanguages",data:"hi hi",}, function(response) {
document.write(response.msg);
});
The background script:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
var returnedLangs;
if (request.action == "getLanguages"){
returnedLangs = getLangs();
alert("got langs " + returnedLangs);
//sendResponse({msg: "goodbye"});
}
});
function getLangs() {
var langs;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {action: "getLanguages"}, function(response) {
langs = response.langs;
alert(langs);
return langs;
});
});
}
The content script code:
chrome.extension.onMessage.addListener( function(request, sender, sendResponse)
{
getLanguages(sendResponse,sendBackLangs);
});
function getLanguages(sendResponse,callback) {
var acceptLangs = [];
chrome.i18n.getAcceptLanguages(function(langs) {
langs.forEach( function(lang) {
acceptLangs.push(lang);
});
callback(sendResponse,acceptLangs);
});
}
function sendBackLangs(sendResponse, acceptedLangs) {
sendResponse({langs: "acceptedLangs"});
}
With the current content script code no response is sent back to the background but if i do sendResponse directly from the chrome.extension.onMessage... function the response is arriving back to the background.
Can anyone help me understand what causes ths behavior and how can i fix it ?
chrome.tabs.sendMessage(tabs[0].id, {action: "getLanguages"}, function(response) {
langs = response.langs;
alert(langs);
return langs; // <---- Return where?
});
See the above snippet. You can't return a value from an asyncronous callback. In fact, this code block just finishes before the inner function executes and getLangs() returns undefined.
What you want to do, however, is doable. You can pass the sendResponse function into the callback to be called later; you just need to indicate to Chrome that you will call it later.
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.action == "getLanguages"){
getLangs(sendResponse); // Pass the callback
return true; // Indicates to Chrome to keep the message channel open
}
});
function getLangs(callback) {
var langs;
chrome.tabs.query(
{active: true, currentWindow: true},
function(tabs) {
chrome.tabs.sendMessage(
tabs[0].id,
{action: "getLanguages"},
function(response) {
// Here it sends it to the content script
callback(response.langs);
}
);
}
);
}
That said, there's absolutely no reason to route the request through background. Just do the tabs.query directly in the popup.
I send a message from a ContextMenu within content.js to background.js. When I send a message, I expect to see an alert of just two variables which are sent with the request. When I send multiple request(few times in a row) I receive alerts including previously sent messages. It seems that all messages are stored somewhere. How do you disable this? I would like to see alerts of only the most recent message.
contents.js:
$(document).mousedown(function(event) {
var url = window.location.href;
var contents = window.getSelection().toString();
switch (event.which) {
case 3:
chrome.runtime.sendMessage({contents: contents, url: url}, function(response) {
//console.log(response.farewell);
});
break;
}
});
background.js
chrome.extension.onMessage.addListener(function (message, sender, sendResponse) {
if (message.url) {
chrome.contextMenus.onClicked.addListener(function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
}
)
}
});
manifest.json
"background": {
"scripts": ["jquery-1.11.1.min.js", "background.js"],
//"page": "background.html",
"persistent": true
},
It's because of this code
chrome.extension.onMessage.addListener(function (message, sender, sendResponse) {
if (message.url) {
chrome.contextMenus.onClicked.addListener(function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
}
)
}
});
What you are saying is that every onMessage event add a listener for onClicked events. So if you send three messages you end up with three testFunc2 methods acting on onClicked events.
Since you are trying to use information from two different asynchronous events. You will have to store one of them temporarily. Something like this would probably work.
var lastMessage;
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
if (message.url) {
lastMessage = message;
} else {
lastMessage = undefined;
}
});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
if(lastMessage !== undefined) {
testFunc2(message, info, tab);
}
});
function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
// cleanup
lastMessage = undefined;
});