Google Chrome Extensions

What are extensions?

(Hint: You're looking at one)

Selfish browser improvements

Make Google Chrome work how you want

Be more productive

Speed up common tasks

Stay on top of things

Get obvious notifications of new content

Tailor your internet

Fix bugs, hack usability

How do I get an extension?

Installing an extension:

Updating an extension:

Updating an extension (worst case):

Chrome extensions follow Chrome principles

#1:
Auto-update

Simple update manifest...

              
<?xml version='1.0' encoding='UTF-8'?>
<gupdate 
    xmlns='http://www.google.com/update2/response' 
    protocol='2.0'>
  <app appid='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'>
    <updatecheck 
        codebase='http://example.com/extension.crx' 
        version='2.0' />
  </app>
</gupdate>
              
            

#2:
Process isolation

#3:
Security sandbox

#4:
Support awesome new technologies

How do you write an extension?

HTML, CSS, and JavaScript

Technology you already know

Like writing a website

(where all of your users have a really fast, standards compliant, modern browser)

Two main components...

#1:
manifest.json

Settings and pointers to your extension's content

               
{
  "name" : "Sample manifest file",
  "version" : "1.0",
  "description" : "A simple manifest.json file",
  "permissions" : [ ... ],
  "icons" : {
    "48" : "icon-48.png",
    "128" : "icon-128.png"
  }
}
              
            

#2:
Background Page

The brains of your extension

Adding a background page...

               
{
  "name" : "Sample manifest file",
  "version" : "1.0",
  "description" : "A simple manifest.json file",
  "permissions" : [ ... ],
  "background_page" : "background.html",
  "icons" : {
    "48" : "icon-48.png",
    "128" : "icon-128.png"
  }
}
              
            

Writing a background page...

               
<!DOCTYPE html>
<html>
  <head>
    <script>
      alert('hello, world!');
    </script>
  </head>
  <body>
  </body>
</html>
              
            

(Will alert once per browser load)

Simple chrome.* APIs

For things that a regular web page can't do:

  • bookmarks
  • history
  • i18n
  • processes
  • tabs / windows
  • etc

Additional HTML permissions

To enhance standards-based APIs:

  • Cross-domain XMLHttpRequest
  • Unlimited FileSystem/IndexedDB quota
  • Notifications, Geolocation permissions

Develop right in Google Chrome

How do extensions hook into Chrome?

UI integration points:

#1:
Browser action

               
"browser_action" : {
  "default_icon": "images/icon19.png", // required
  "default_title": "I'm a title"       // optional
},
              
            

#2:
Page action

               
"page_action" : {
  "default_icon": "images/icon19.png", // required
  "default_title": "I'm a title"       // optional
},
              
            

Browser vs. Page Action

You must choose wisely (because you only get one):

Use a page action when you want to expose page-specific functionality.

Use a browser action if your extension does not interact with the current page.

#3:
Popup

               
"page_action" : {
  "default_icon": "images/icon19.png", // required
  "default_title": "I'm a title",      // optional
  "default_popup": "popup.html"
},
              
            

#4:
Notifications

{
  "name" : "Sample manifest file",
  "version" : "1.0",
  "permissions" : [ notifications ],
}
              
            

#5:
Context Menus

"permissions": [ "contextMenus" ],
"icons": {
  "16": "icon-16.png",
  "48": "icon-small.png",
  "128": "icon-large.png"
},
              
            

#6:
Omnibox

"omnibox": { "keyword" : "omnix" },
"icons": {
  "16": "icon-16.png",
  "48": "icon-small.png",
  "128": "icon-large.png"
},
              
            

And finally, one more view...

...is the webpage itself

#7:
Content Scripts

manifest.json
"content_scripts": [{ 
  "matches": ["http://blog.flickr.net/*"],
  "css" : ["mystyles.css"],
  "js" : ["myscript.js"],
  "run_at" : "document_start"
}],

mystyles.css
a img { -webkit-transition: all 0.5s ease-in-out; }
a img:hover { -webkit-transform: scale(2); z-index: 1000; }

myscript.js
window.addEventListener('load', function() { 
  alert('Hover over images!'); 
});

Match Patterns

How do these parts fit together?

Manifest identifies source files

The background page calls chrome.* functions to initialize the extension
and perform background tasks.

Sharing windows

The background page and most other extension pages like the popup can share window objects.

background.html -> popup.html
popups = chrome.extension.getViews({ 'type' : 'popup' });
popups.forEach(win) {
  // Win points to the popup's Window object.
};

popup.html -> background.html
var bg = chrome.extension.getBackgroundPage();
// Now bg points to the background page's window

Sandboxed windows

However, background pages and content scripts are sandboxed. Developers must use message passing instead:

contentscript.js
function onResponse(resp) { console.log(resp.welcome); }
chrome.extension.sendRequest({myname: "Bob"}, onResponse);

background.html
function onRequest(request, sender, sendResponse) {
  sendResponse({welcome: "Hello, " + request.myname});
};
chrome.extension.onRequest.addListener(onRequest);

Isolated worlds

Content scripts may directly access the DOM of the page they are running on, but cannot directly access JavaScript objects.

DOM
var anchors = document.querySelectorAll('a'); 

JavaScript
var script = document.createElement('script'); 
script.innerText = 'code to execute'; 
document.body.appendChild(script);

Limited privilege

Content scripts also may not use any chrome.* APIs, except those in chrome.extension.*.

Typically, a content script only routes data between the current HTML page and the background page of an extension.

Asynchronous code

Many of these requests cross process boundaries. This is why much of the chrome.* API uses asynchronous calls:

chrome.windows.getAll({}, function(window) {
  // This code is called asynchronsly
});
            

http://code.google.com/chrome/extensions/

Extensions to optimize your life

Template 1: Status Monitor

  • Monitor a site for status changes.
     
  • Use cases:
    • queues
    • messaging

  • Technologies:
    • cross-domain XHR
    • background page
    • notifications
    • browser action

  • Challenges: Not all sites have an API.
     
  • Example: Chromium Buildbot Monitor.

Buildbot background page

            
function requestStatus() {
  requestURL(statusURL, updateStatus);
  setTimeout(requestStatus, 30000);
}

function requestURL(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function(state) {
    if (xhr.readyState == 4 && xhr.status == 200) {
      callback(xhr.responseText);
    } else {
      chrome.browserAction.setBadgeText({text:"?"});
      chrome.browserAction.setBadgeBackgroundColor({
        color:[0,0,255,255]
      });
    }
  }
  xhr.open("GET", url, true);
  xhr.send({});
}
            
          

Template 2: Workflow Automation

  • Use extensions to help ease repetitive tasks.
     
  • Use cases:
    • form filling
    • repeated navigation

  • Technologies:
    • chrome.tabs.*
    • content scripts

Reviews background page

            
function setGalleryTab(url) {
  chrome.tabs.update(gallery_tab.id, {'url' : url});
};

function onTab(tab) {
  gallery_tab = tab;
  chrome.windows.create({ 
    'url':'popup.html', 
    'left':0, 'top':200, 'width':500, 'height':250 
  }, onPopupWindow);
};

function createTabs() {
  if (gallery_tab == null && popup_tab == null)
    chrome.tabs.create({'url' : 'index.html'}, onTab);
};

chrome.browserAction.onClicked.addListener(createTabs);
            
          

Template 3: UI "fixes"

  • Add functionality to existing site UI.
     
  • Use cases:
    • form filling
    • repeated navigation

  • Technologies:
    • content scripts

  • Challenges: need to keep up with product UI.
     

Calendar input content script

            
function waitFor(node, selector, callback) {
  var handler = getNodeInsertedHandler(callback);
  node.addEventListener('DOMNodeInserted', handler, false);
};

function getNodeInsertedHandler(callback) {
  return function(evt) {
    var target = node.querySelector(selector);
    if (target) {
      callback(target);
    }
  };
};

function onNode(node) { ... };

waitFor(document.body, '.ep-dp-calendar', onNode);
waitFor(document.body, '.ep-dp-descript', onNode);
            
          

Template 4: Quick reference

  • Fast lookups for information.
     
  • Use cases:
    • documentation
    • knowledge base

  • Technologies:
    • omnibox
    • chrome.tabs.*

  • Example: Extension docs search.

Docs search background page

            
APISearchCorpus.prototype.findMatch_ = function(keywords, name) {
  var style = [];
  var indexFrom = 0;
  for (var i = 0; i < keywords.length; i++) {
    var keyword = keywords[i].toLowerCase();
    var start = name.toLowerCase().indexOf(keyword, indexFrom);
    if (start == -1) { return null; }
    var end = start + keyword.length + 1;

    style.push(name.substring(indexFrom, start))
    style.push('<match>');
    style.push(name.substring(start, end));
    style.push('</match>');

    indexFrom = end;
  }
  style.push(name.substring(indexFrom));
  return style.join('');
};
            
          

What can an extension do?

Options pages

              
<script>
  function storeValue() {
    var optInput = document.getElementById('myoption');
    localStorage['myoption'] = optInput.value;
  };
</script>
<input id='myoption' onkeyup='storeValue()' />
<script>
  var optInput = document.getElementById('myoption');
  optInput.value = localStorage['myoption'] || "default";
</script>
              
            

Override pages

Experimental APIs

Disabled by default, need to launch Chrome with --enable-experimental-extension-apis

and require the experimental permission.

  • experimental.clipboard
  • experimental.infobars
  • experimental.processes
  • experimental.proxy
  • experimental.sidebar
  • experimental.webNavigation
  • experimental.webRequest

Looking for feedback!

Happy Coding!

See you at code.google.com/chrome/extensions/

Credits

The following materials were used in this presentation.

Fonts