Enhance your browser

Chrome Extensions

Created by Mikalai Ausiannikau

What are extensions?

Extensions are small software programs that can modify and enhance the functionality of the browser.


  • You can add functionality to the browser without diving deeply into native code
  • You can use core web technologies that you're already familiar with
  • Unlike ordinary web apps, extensions don't need to depend on content from the web

Extension structure

  • A manifest file
  • Optional: One or more HTML files (unless the extension is a theme)
  • Optional: One or more JavaScript files
  • Optional: Any other files your extension needs (e.g., image files)

What is manifest?

The manifest file, called manifest.json, gives information about the extension, such as the most important files and the capabilities that the extension might use

Manifest format

							
{
  // Required
  "manifest_version": 2,
  "name": "My Extension",
  "version": "versionString",

  // Recommended
  "default_locale": "en", // must be absent if no _locales directory
  "description": "A plain text",
  "icons": { 
  	"16": "icon16.png", 
  	"48": "icon48.png", 
  	"128": "icon128.png" 
  },
  ...
}
							
						

Supported manifest fields

  manifest_version
  name
  version
  default_locale
  description
  icons
  browser_action
  page_action
  author
  automation
  background
  chrome_settings_overrides
  chrome_ui_overrides
  chrome_url_overrides
  commands
  content_pack
  content_scripts
  content_security_policy
  converted_from_user_script
  current_locale
  devtools_page
  externally_connectable
  homepage_url
  import
  incognito
  input_components
  key
  minimum_chrome_version
  nacl_modules
  oauth2
  offline_enabled
  omnibox
  optional_permissions
  options_page
  options_ui
  permissions
  platforms
  plugins
  requirements
  sandbox
  script_badge
  short_name
  signature
  spellcheck
  storage
  system_indicator
  tts_engine
  update_url
  web_accessible_resources
						

chrome.* API

In addition to having access to all the APIs that web pages and apps can use, extensions can also use Chrome-only APIs (often called chrome.* APIs) that allow tight integration with the browser.

Stable API

  accessibilityFeatures
  alarms
  bookmarks
  browserAction
  browsingData
  commands
  contentSettings
  contextMenus
  cookies
  debugger
  declarativeContent
  desktopCapture
  devtools.inspectedWindow
  devtools.network
  devtools.panels
  downloads
  enterprise.platformKeys
  events
  extension
  extensionTypes
  fontSettings
  gcm
  history
  i18n
  identity
  idle
  input.ime
  management
  notifications
  omnibox
  pageAction
  pageCapture
  permissions
  power
  privacy
  proxy
  pushMessaging
  runtime
  sessions
  storage
  system.cpu
  system.memory
  system.storage
  tabCapture
  tabs
  topSites
  tts
  ttsEngine
  types
  webNavigation
  webRequest
  webstore
  windows
						

Beta API

  declarativeWebRequest
						

Dev API

  automation
  fileSystemProvider
  infobars
  location
  processes
  signedInDevices
						

Experimental API

  experimental.devtools.audits
  experimental.devtools.console
						

Background page


Invisible page that holds the main logic of the extension.

							
{
  ...
  "background": {    
    "scripts": ["background.js"]	
  },
  ...
}
							
						

or

							
{
  ...
  "background": {    
    "page": "background.html"
  },
  ...
}
							
						

Types of background pages

  • Persistent Background Page
  • Event Page
							
{
  ...
  "background": {    
    "persistent": false,
	// "true" (by default) - Persistent Background Page 
	// "false" - Event Page
  	...
  },
  ...
}
							
						

If you need the browser to start up background page early

							
{
  ...
  "permissions": [ "background" ]
  ...
}
							
						

Content scripts

It is some JavaScript that executes in the context of a page that's been loaded into the browser to interact with this page.

							
{
  ...
  "content_scripts": [{
      "matches": ["http://www.google.com/*"], // Required.
      "css": ["mystyles.css"], // Optional.
      "js": ["jquery.js", "myscript.js"], // Optional.	  
      // Optional. "document_start", "document_end", "document_idle".
      "run_at": "document_idle"
  }]
}
							
						

Limitations

Content scripts are executed in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page.

Browser and Page actions

							
{
  ...
  "browser_action": {
	"default_title": "title",
	"default_icon": {
		"19": "images/icon19.png",
		"38": "images/icon38.png"
	},
	"default_popup": "popup.html"
  }
}
							
						
							
{
  ...
  "page_action": {
	"default_title": "title",
	"default_icon": {
		"19": "images/icon19.png",
		"38": "images/icon38.png"
	},
	"default_popup": "popup.html"
  }
}
							
						

What to choose?

  • Browser action - when the extension is relevant to most pages
  • Page action - when the extension's icon should appear or disappear, depending on the page

Key points

  • Each extension can have at most one browser action or page action.
  • The both browser and page actions can have an icon, a tooltip, and popup.
  • Browser action can also have a badge but page action can't have. In addition, page actions can appear and disappear.

API


chrome.browserAction.*

							
chrome.browserAction.set[get]Title(object details[, function callback]);
chrome.browserAction.set[get]BadgeText(object details[, function callback]);
chrome.browserAction.set[get]BadgeBackgroundColor(object details[, function callback]);
chrome.browserAction.set[get]Popup(object details[, function callback]);
chrome.browserAction.enable[disable](integer tabId);
chrome.browserAction.setIcon(object details);

chrome.browserAction.onClicked.addListener(function(tab) {...});
							
						

chrome.pageAction.*

							
chrome.pageAction.set[get]Title(object details[, function callback]);
chrome.pageAction.set[get]Popup(object details[, function callback]);
chrome.pageAction.show[hide](integer tabId);
chrome.pageAction.setIcon(object details);

chrome.pageAction.onClicked.addListener(function(tab) {...});
							
						

Communication between pages


  • Direct access
  • Simple one-time requests
  • Long-lived connections
  • Cross-extension messaging
  • Sending messages from web pages

Direct access


The extension pages can make direct function calls to each other since all of them are executed in same process on the same thread.

							
// returns the JavaScript 'window' object for the background page
// running inside the current extension
var bgp = chrome.extension.getBackgroundPage();

// returns an array of the JavaScript 'window' objects for each of the pages
// running inside the current extension
var views = chrome.extension.getViews({ type: "popup" });
							
						

Once a page has a reference to other pages within the extension, the first page can invoke functions on the other pages, and it can manipulate their DOMs.

							
// If the background page is an event page, 
// the system will ensure it is loaded before calling the callback. 
// If there is no background page, an error is set.
chrome.runtime.getBackgroundPage(function(Window backgroundPage) {...});
							
						

Simple one-time requests

							
// Send a request from a content script:
chrome.runtime.sendMessage({greeting: "hello"}, function(response) { });

// Send a request from background page to a content script:
chrome.tabs.sendMessage(tabId, {greeting: "hello"}, function(response) { });

// Listener to handle the message from both a content script / background page
chrome.runtime.onMessage.addListener(function(request, sender, sendResponseFn) { });
							
						

Long-lived connections

							
// connect inside extension page
var port = chrome.runtime.connect({ name: "any_name" });

// connect inside content script
var port = chrome.tabs.connect(tabId: "tabId_value", { name: "any_name" })

// handle incoming connections inside both extension page and content script
chrome.runtime.onConnect.addListener(function(port) { });

// manually call disconnect
port.disconnect();
port.onDisconnect.addListener(function() { });

// send and receive messages
port.postMessage({ greeting: "hello" });
port.onMessage.addListener(function(msg) { });
							
						

Cross-extension messaging

							
// connect to another extension providing its extension ID
var port = chrome.runtime.connect(extensionId, { name: "any_name" });

// handle external incoming connections
chrome.runtime.onConnectExternal.addListener(function(port) { });

// send and receive messages for long-lived connections
port.postMessage({ greeting: "hello" });
port.onMessage.addListener(function(msg) { });

// For simple requests:
chrome.runtime.sendMessage(extensionId, {greeting: hello},
  function(response) {});

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) { 
});
							
						

Sending messages from web pages

							
{
  "externally_connectable": {
    // The IDs of extensions or apps that are allowed to connect.
    // The wildcard "*" will allow all extensions and apps to connect.
    "ids": [
      "*"
    ],
    // The URL patterns for web pages that are allowed to connect. 
    // If left empty or unspecified, no web pages can connect.
    // The URL pattern must contain at least a second-level domain.
    "matches": [ "*://*.google.com/*"]
  }
}
							
						

If there is no externally_connectable, all extensions and apps can connect, but no webpages can connect.

If you use externally_connectable and "ids": ["*"] is not specified then other extensions will lose the ability to connect to it.

Content Security Policy (CSP)

CSP introduces some fairly strict policies that will make extensions more secure by default, and provides you with the ability to create and enforce rules governing the types of content that can be loaded and executed by your extensions and applications.

							
{
  ...,
  "content_security_policy": "[POLICY STRING GOES HERE]"
  ...
}
							
						

Default Policy Restrictions

							
{
  ...,
  "content_security_policy": "script-src 'self'; object-src 'self'"
  ...
}
							
						
  • Eval and related functions are disabled
  • Inline JavaScript will not be executed
  • Only local script and and object resources are loaded


CSP applies to the background pages and event pages of the extension.

Relaxing the default policy

							
// Remote Script
"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"

// Evaluated JavaScript
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
							
						

Permissions

To use most chrome.* APIs and extension capabilities, your extension must declare its intent in the manifest, often in the "permissions" field.

Some of these declarations result in a warning when a user installs or autoupdate your extension.

Required vs Optional Permissions

  • required permissions - use when they are needed for your extension's basic functionality
  • optional permissions - use when they are needed for optional features in your extension


Declare permissions in the manifest

							
{
    ...
    "permissions": [ "webRequest" ],

    "optional_permissions": [ "tabs" ],
    ...
}
							
						

Autoupdate with new required permissions

When the extension autoupdates, the increased permissions cause the extension to be disabled until the user re-enables it.

Check current permissions

							
chrome.permissions.contains({
    permissions: ['tabs']
}, function(result) {
    // The callback argument will be true if the extension has the permissions.
});
							
						

you can also get an array of all granted permissions

							

chrome.permissions.getAll(function(permissions) {
    // The callback argument will be true if the extension has the permissions.
})
							
						

Request optional permissions

							
chrome.permissions.request({
    permissions: ['tabs']
}, function(granted) {
    // The callback argument will be true if the user granted the permissions.
});
							
						

IMPORTANT: Permissions must be requested from inside a user gesture, like a button's click handler.


Themes

A theme is a special kind of extension that changes the way the browser looks. Themes are packaged like regular extensions, but they don't contain JavaScript or HTML code.

Manifest for a theme

							
{
  "theme": {
    "images" : {
      "theme_frame" : "images/theme_frame_camo.png",
      "theme_frame_overlay" : "images/theme_frame_stripe.png",
      "theme_toolbar" : "images/theme_toolbar_camo.png",
      "theme_ntp_background" : "images/theme_ntp_background_norepeat.png",
      "theme_ntp_attribution" : "images/attribution.png"
    },
    "colors" : {
      "frame" : [71, 105, 91],
      "toolbar" : [207, 221, 192],
      "ntp_text" : [20, 40, 0],
      "ntp_link" : [36, 70, 0],
      "ntp_section" : [207, 221, 192],
      "button_background" : [255, 255, 255]
    },
    "tints" : {
      "buttons" : [0.33, 0.5, 0.47]
    },
    "properties" : {
      "ntp_background_alignment" : "bottom"
    }
  }
}
							
						

Packaging and distribution

Extensions are packaged as signed ZIP files with the file extension ".crx".

When you package an extension, the extension is assigned a unique key pair. The extension's ID is based on a hash of the public key. The private key is used to sign each version of the extension and must be secured from public access.


How to publish

  • Distribute a non-public version of the extension
  • Publish the extension using the Chrome Developer Dashboard

Creating own package

  • Via Chrome Extensions tab:

    1. Go to Settings->Extensions tab (chrome://extensions)
    2. Enable "Developer mode" checkbox at the top.
    3. Click the "Pack extension" button and specify the path to the extension dir (you don't need to specify the path to private key file for the first time).
    4. Click "Package" button and two files (".crx" - extension and ".pem" - private key) will be created.

  • Via command line:

    									
    chrome.exe --pack-extension=C:\myext --pack-extension-key=C:\myext.pem
    									
    								

Chrome Developer Dashboard

  1. Create a ZIP archive of the root extension directory
  2. Go to Chrome Developer Dashboard (https://chrome.google.com/webstore/developer/dashboard)
  3. Click the "Add new item" button, choose created ZIP file and click "Upload"
  4. Fill out the form about your extension and upload images.
  5. Before you publish your first app, you must pay a one-time $5 developer signup fee.
  6. Test the extencion and click the "Publish" link to publish your app's listing in the Chrome Web Store.

Autoupdating

  • A manifest should contain an "update_url" field, pointing to a location for doing update checks.
  • The content returned by an update check is an update manifest XML document listing the latest version of an extension.


The browser makes a request to that URL looking for an update manifest XML file every few hours. The newer version of the extension is downloaded and installed automatically.

Update URL

							
{
  "name": "My extension",
  ...
  "update_url": "http://myhost.com/myext.xml",
  ...
}
							
						

Update manifest

							


  
    
  

							
						

Check for updates

  • Automatically by browser

    									
    chrome.exe --extensions-update-frequency=45
    									
    								
  • Programmatically

    									
    chrome.runtime.requestUpdateCheck(function(status, details) {
      if (status == "update_available") {
        console.log("update pending...");
      } else if (status == "no_update") {
        console.log("no update found");
      } else if (status == "throttled") {
        console.log("Oops, I'm asking too frequently.");
      }
    });
    									
    								

Links

Questions?

BY Mikalai Ausiannikau