Making Your Own Chrome Extension

What making my first extension looked like

High Level View

Content Script

  • Run in their own context: cannot call functions in webpage's context
  • Have access to DOM
  • Can be useful on its own
  • Can communicate with background script
  • Limited access to APIs

Demo

Popup

  • A web page on its own
  • Context is only initiazlized when opened
  • Can communicate with inspected window
  • Can communicate with background script
  • Usually requires a background script to be useful
  • Limited access to APIs

Popup Manifest

{
    "manifest_version": 2,
    "version": "1.7.8.2",
    "name": "Play to Kodi",
    "description": "Play, queue and remote control your favourite online media on Kodi / XBMC.",
    "options_page": "options.html",
    "permissions": [ "tabs", "http://*/*", "contextMenus" ],

    // The icon on the extension bar is a `browser action`
    "browser_action": {
        "default_icon": "images/icon.png",
        "default_popup": "remote.html"
    }
}

Devtool Panel

  • A web page on its own
  • Context is only initiazlized when opened
  • Can communicate with inspected window
  • Can communicate with background script
  • Usually requires a background script to be useful
  • Limited access to APIs

Devtool Manifest

{
    "manifest_version": 2,
    "name": "Mogul",
    "description": "A debugging tool for Kandy.js on Chrome.",
    "version": "0.1.0",
    "author": "Kandy.io",
    "icons": {
        "16": "images/icon_16.png",
        "48": "images/icon_48.png",
        "128": "images/icon_128.png"
    },

    // How to declare a devtool page
    "devtools_page": "main.html"
}

Background Page

  • No UI
  • Always running*
  • Can receive messages for any component
  • Full access to any API requested in the manifest
  • This is where you save your state

Background Page Manifest

{
    "manifest_version": 2,
    "name": "Mogul",
    "description": "A debugging tool for Kandy.js on Chrome.",
    "version": "0.1.0",
    "author": "Kandy.io",
    "icons": {
        "16": "images/icon_16.png",
        "48": "images/icon_48.png",
        "128": "images/icon_128.png"
    },
    "devtools_page": "main.html",

    // How to declare a background page
    "background": {
      "scripts": ["background.js"],
      "persistent": false  // This is important for performance
    }
}

Back to Messaging

Devtool-to-Webpage

chrome.devtools.inspectedWindow.eval(
  "jQuery.fn.jquery",
   function(result, isException) {
     if (isException)
       console.log("the page is not using jQuery");
     else
       console.log("The page is using jQuery v" + result);
   }
);

Content Script <-> Webpage

// Send
var event = new CustomEvent('KandyEvent', {detail: action});
window.dispatchEvent(event);

// Receive
window.addEventListener('KandyEvent', function(event){
    console.log(event.detail);
}, false);

Simple Request/Response

// Content Script
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});

// Bacground Script
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse({farewell: "goodbye"});
  }
);

2-way Messaging (Ports)

// Content Script
var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  console.log(msg);
});

// Bacground Script
chrome.runtime.onConnect.addListener(function(port) {
  port.postMessage({joke: "Knock knock"});
  port.onMessage.addListener(function(msg) {
    console.log(msg);
  });
});

Jean-Luc Martin

@Mustack_

I'd love to hear your feedback about this talk.

Questions?

Chrome Extension Dev

By mustack

Chrome Extension Dev

  • 773