Thursday, May 23, 2013

Sending Messages Between the Background and the Content Script of a Chrome Extension

As a Chrome Extension will usually persist information longer than the duration that the content script is running on a page, such as for database persistence, and because the background script of an extension has greater access to the Chrome API than a content script, (primarily for security reasons), there exists the ability to communicate between the two using messages.

There are two types of message sending as explained in the Extensions Developer Guide – simple one-time requests and long-lived connections. This post will focus on simple one-time requests and sending a message from the content script to the background and sending a message back to the content script in response.

In this example, when the user presses Ctrl-Shift-Z a message will be sent from the content script to the background script. The background script receives the message, adds to the message and sends a message back to the content script.

Firstly, the manifest.json file for the extension specifies our background script and content script files to be used in the “content_scripts” and “background” sections respectively, as shown below:

 
 
{
  "name": "Sending Messages Test",
  "version": "1.0",  
  "description": "Send a Message to background.js from contentscript.js and send reply",
  
  "permissions": ["tabs"],
  
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["contentscript.js"]
    }
  ],
  
  "background": { "scripts": ["background.js"] },

  "manifest_version": 2
}
 


The content script is what is injected into the current web page and is where the process is initiated from. An event listener is added to the ‘keyup’ keyboard event and calls the function doKeyPress() when triggered which in turn sends the message. 

In order to send the message to the background script, part of the chrome.extension API is available within the content script. Using the function chrome.extension.sendRequest() our message is sent to the background script. Any object can be passed to this method that can be serialised into a JSON string and that does not contain circular references. 

In order to receive a message back from the background script a function of the chrome.runtime API is used. The function chrome.runtime.onMessage.addListener() allows us to specify a function to handle a message from the background script. In our case, it shows an alert with the response from the background. 

The contentscript.js file is shown below:

 
 
trigger_key = 90; //ASCII key code for the letter 'Z'
contentScriptMessage = "Skinner Said the teachers will crack any minute";

if (window == top) {
 window.addEventListener('keyup', doKeyPress, false); 
}

function doKeyPress(e){
 if (e.shiftKey && e.ctrlKey && e.keyCode == trigger_key){ 
  alert("Contentscript is sending a message to background script: '" + contentScriptMessage  + "'");
  chrome.extension.sendRequest({message: contentScriptMessage});
 }
}

chrome.runtime.onMessage.addListener(
 function(request, sender) {
  alert("Contentscript has received a message from from background script: '" + request.message + "'");
  });
 



Our background script has two functions. To listen for messages from the content script and to send a reply once a message is received. To listen for messages, the function chrome.extension.onRequest.addListener() is used which listens for messages from the content script and calls our function returnMessage to send a message back to the content script. 

In order to send a message back to the contentscript, the background script needs to determine the id of the tab to send the message back to and so uses the chrome.tabs API to determine the currently open tab using chrome.tabs.getSelected(null, function(tab) { … }) The inner function to be called on the selected tab then calls the function chrome.tabs.sendMessage() with the id of the open tab and our return object as arguments. This is then received by the message listener in our contentscript as explained earlier.


 
 
var backgroundScriptMessage = " purple monkey dishwasher";

chrome.extension.onRequest.addListener(function(request, sender) 
{
 alert("Background script has received a message from contentscript:'" + request.message + "'");
 returnMessage(request.message);
});

function returnMessage(messageToReturn)
{
 chrome.tabs.getSelected(null, function(tab) {
  var joinedMessage = messageToReturn + backgroundScriptMessage;  
  alert("Background script is sending a message to contentscript:'" + joinedMessage +"'");
  chrome.tabs.sendMessage(tab.id, {message: joinedMessage});
 });
}
 


The complete project which can be loaded as an unpacked extension into Chrome can be downloaded from here.

The sequence of alerts that will be seen when pressing Ctrl-Shift-Z are: