Call background function of Chrome extension from a site Call background function of Chrome extension from a site google-chrome google-chrome

Call background function of Chrome extension from a site


Before a web page is able to call a background page's function, the following problems need to be solved:

  1. Be able to use hello(); from a web page. This is done by injecting a script defining hello using Content scripts. The injected function communicates with the content script using a custom event or postMessage.
  2. The content script needs to communicate with the background. This is implemented through chrome.runtime.sendMessage.
    If the web page needs to receive a reply as well:
  3. Send a reply from the background page (sendMessage / onMessage, see below).
  4. In the content script, create a custom event or use postMessage to send a message to the web page.
  5. In the web page, handle this message.

All of these methods are asynchronous, and have to be implemented through callback functions.

These steps need to be designed carefully. Here's a generic implementation which implements all of the above steps. What you need to know about the implementation:

  • In the code-to-be-injected, use the sendMessage method whenever the content script need to be contacted.
    Usage: sendMessage(<mixed message> [, <function callback>])

contentscript.js

// Random unique name, to be used to minimize conflicts:var EVENT_FROM_PAGE = '__rw_chrome_ext_' + new Date().getTime();var EVENT_REPLY = '__rw_chrome_ext_reply_' + new Date().getTime();var s = document.createElement('script');s.textContent = '(' + function(send_event_name, reply_event_name) {    // NOTE: This function is serialized and runs in the page's context    // Begin of the page's functionality    window.hello = function(string) {        sendMessage({            type: 'sayhello',            data: string        }, function(response) {            alert('Background said: ' + response);        });    };    // End of your logic, begin of messaging implementation:    function sendMessage(message, callback) {        var transporter = document.createElement('dummy');        // Handles reply:        transporter.addEventListener(reply_event_name, function(event) {            var result = this.getAttribute('result');            if (this.parentNode) this.parentNode.removeChild(this);            // After having cleaned up, send callback if needed:            if (typeof callback == 'function') {                result = JSON.parse(result);                callback(result);            }        });        // Functionality to notify content script        var event = document.createEvent('Events');        event.initEvent(send_event_name, true, false);        transporter.setAttribute('data', JSON.stringify(message));        (document.body||document.documentElement).appendChild(transporter);        transporter.dispatchEvent(event);    }} + ')(' + JSON.stringify(/*string*/EVENT_FROM_PAGE) + ', ' +           JSON.stringify(/*string*/EVENT_REPLY) + ');';document.documentElement.appendChild(s);s.parentNode.removeChild(s);// Handle messages from/to page:document.addEventListener(EVENT_FROM_PAGE, function(e) {    var transporter = e.target;    if (transporter) {        var request = JSON.parse(transporter.getAttribute('data'));        // Example of handling: Send message to background and await reply        chrome.runtime.sendMessage({            type: 'page',            request: request        }, function(data) {            // Received message from background, pass to page            var event = document.createEvent('Events');            event.initEvent(EVENT_REPLY, false, false);            transporter.setAttribute('result', JSON.stringify(data));            transporter.dispatchEvent(event);        });    }});

background.js

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {    if (message && message.type == 'page') {        var page_message = message.message;        // Simple example: Get data from extension's local storage        var result = localStorage.getItem('whatever');        // Reply result to content script        sendResponse(result);    }});

A Chrome extension is not complete without a manifest file, so here's the manifest.json file which I used to test the answer:

{    "name": "Page to background and back again",    "version": "1",    "manifest_version": 2,    "background": {        "scripts": ["background.js"]    },    "content_scripts": [{        "matches": ["http://jsfiddle.net/jRaPj/show/*"],        "js": ["contentscript.js"],        "all_frames": true,        "run_at": "document_start"    }]}

This extension was tested at http://jsfiddle.net/jRaPj/show/ (containing hello(); as seen in the question), and shows a dialog saying "Background said: null".
Open the background page, use localStorage.setItem('whatever', 'Hello!'); to see that the message is correctly changed.


There is a builtin solution to Send messages from web pages to the extension

mainfest.json

"externally_connectable": {  "matches": ["*://*.example.com/*"]}

Web page:

// The ID of the extension we want to talk to.var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";// Make a simple request:chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},  function(response) {    if (!response.success)      handleError(url);  });

Extension's background script:

chrome.runtime.onMessageExternal.addListener(  function(request, sender, sendResponse) {    if (sender.url == blacklistedWebsite)      return;  // don't allow this web page access    if (request.openUrlInEditor)      openUrl(request.openUrlInEditor);  });


No, with your above code because of background page(s) architecture

Yes with content scripts

Demonstration Using Content Scripts

manifest.json

Registering content scripts myscripts.js

{"name": "NFC","description": "NFC Liken","version": "0.1","manifest_version": 2,"permissions": ["tabs", "http://*/", "https://*/"],"content_scripts": {    "matches": "http://www.example.com/*",    "js": [ "myscript.js"]  },"browser_action": {"default_icon": "sync-icon.png","default_title": "I Like I Tag"}}

Let me know if you need more information.