1

I'm trying to get basic message passing to work in a Chrome extension. There are a number of related questions on SF on this (most notably here: Basic google chrome extension message passing not working), but unfortunately the advice there seems not to work for me.

Here's my manifest.json file:
{
  "name": "Steve Screenshot",
  "description": "Do something",
  "version": "0.1",
  "manifest_version": 2,
  "content_scripts": [
    {
      "matches" : ["*://*/*"],
      "js": ["simple.js"]
    }
  ]
}

And my simple.js file:

chrome.runtime.onMessage.addListener(function(request, sender, callback) {
  console.log('message received');
});

// Invoke it!!!
chrome.runtime.sendMessage({
  msg: 'whatever'
}, function(response) {
  console.log('message sent');
});

At runtime, the console log shows the "message sent" message but NOT the "message received" message. To the best of my understanding, I am ?correctly? invoking chrome.runtime.onMessage/sendMessage. Can anyone comment?

Thanks, --Steve

Community
  • 1
  • 1
Stephen Gross
  • 5,274
  • 12
  • 41
  • 59

1 Answers1

1

The problem is that you are trying to use chrome.runtime.sendMessage to send a message to a content script. You cannot send messages to content scripts using runtime.sendMessage, you must use tabs.sendMessage. (Read about that here).

A good setup for message passing is to use a background page as sort of a 'router' for your messages. When you need to pass a message to content scripts you do so from the background page using the tabs api. For a simple test, you could add a tabs.query call in the background script to send a message to ALL content scripts like so:

chrome.tabs.query({}, function(tabs) {
  for(var i = 0; i < tabs.length; i++) {
    chrome.tabs.sendMessage(tabs[i].id, {msg: 'whatever'});
  }
}

To send messages to individual content scripts will require some additional logic but is very doable (one way is to maintain some associative queue structure in the background page).

Also, note that you can use chrome.runtime.sendMessage from inside a content script, but this will send a message to event listeners in your extension that are not inside content scripts. (So you can send a message to the background page using this method)

berrberr
  • 1,914
  • 11
  • 16
  • Thanks for the suggestion. Is there anything special I need to do to make chrome.tabs available? I tried using chrome.tabs.sendMessage, but it looks like chrome.tabs is undefined. – Stephen Gross Feb 18 '14 at 23:19
  • Another follow-up: I tried the suggested split between content and background scripts: manifest.json: ... "background": { "scripts": ["receiver.js"], "persistent" : true }, ... receiver.js: chrome.runtime.onMessage.addListener(function(request, sender, callback) { sessionStorage.setItem("request", request.msg); }); simple.js: sessionStorage.setItem('request', ''); chrome.runtime.sendMessage({ msg: 'whatever' }, function(response) { console.log(sessionStorage.getItem('request')); }); It looks like the listener is not being called; getItem() returns undefined. – Stephen Gross Feb 18 '14 at 23:26
  • For tabs to work you need to add `tabs` to the `permissions` section of your manifest. Read about that near the top [here](http://developer.chrome.com/extensions/tabs). Re: your second post - remember that `sendMessage` does **not** send messages to content scripts, so in your background page you must use `tabs.sendMessage`. Try adjusting the permissions and see if the initial example works. Also read that page I linked, the docs are pretty good. – berrberr Feb 19 '14 at 02:03
  • I did add "tabs" to permissions, but am still getting "Uncaught ReferenceError: tabs is not defined" error (tried both chrome.tabs.sendMessage and tabs.sendMessage). Are you sure there's nothing else I need to do to make the tabs interface available? Although looking here (http://stackoverflow.com/questions/15034859/chrome-tabs-returns-undefined-in-content-script) it sounds like tabs is not available in a content script anyway. – Stephen Gross Feb 19 '14 at 03:21
  • Follow-up: I have used alerts to confirm that my background script is indeed being called. However, it looks like sessionStorage isn't shared/propagated between the content and background scripts. Do you know if it is supposed to be shared? – Stephen Gross Feb 19 '14 at 03:26
  • Right, you can't call `tabs` from the content script - you call it from the background page to send the message *to* the content script. You are correct that the `tabs` API is inaccessible from content scripts, but in your content script you should be using `chrome.runtime` to send and receive messages from the background page. Re: session storage - I'm not sure I've never used it. I have, however, used the `chrome.storage` API which is accessible from content scripts and is easy to work with. That might be worth checking out. – berrberr Feb 19 '14 at 03:36
  • Ok, finally made some progress. My content script sends a simple message with a callback that alert()'s the response. chrome.runtime.sendMessage({ msg: 'whatever'}, function (response) { alert(response); }); The response script directly invokes callback() when complete. This seems to work. However, if the background script indirectly calls the callback it appears to fail: chrome.runtime.onMessage.addListener( function(request, sender, callback) { chrome.storage.local.set({ "x": "y"}, function() { callback('done'); }); } ); Any thoughts on what I'm doing wrong here? – Stephen Gross Feb 19 '14 at 04:03