forked from mirrors/gecko-dev
		
	List of changes: - renamed a section for clarity (WebExtensions Experiments -> Adding Experimental APIs in Privileged Extensions) - fixed a few typos because I think we should consistently use the name WebExtensions (with a `s`) when it is followed by API(s) at least - added a link to the xpi-manifest repo in a notice (main repo, not the `docs/` folder or a markdown file because that may change) - Experimental APIs is referenced in the section that has been edited so made it clear what is an Experimental API vs Built-in (hopefully). Also kept the reference to "WebExtensions Experiment" (which seems to be an alias) Differential Revision: https://phabricator.services.mozilla.com/D146537
		
			
				
	
	
		
			275 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
.. _basics:
 | 
						|
 | 
						|
API Implementation Basics
 | 
						|
=========================
 | 
						|
This page describes some of the pieces involved when creating
 | 
						|
WebExtensions APIs.  Detailed documentation about how these pieces work
 | 
						|
together to build specific features is in the next section.
 | 
						|
 | 
						|
The API Schema
 | 
						|
--------------
 | 
						|
As described previously, a WebExtension runs in a sandboxed environment
 | 
						|
but the implementation of a WebExtensions API runs with full chrome
 | 
						|
privileges.  API implementations do not directly interact with
 | 
						|
extensions' Javascript environments, that is handled by the WebExtensions
 | 
						|
framework.  Each API includes a schema that describes all the functions,
 | 
						|
events, and other properties that the API might inject into an
 | 
						|
extension's Javascript environment.
 | 
						|
Among other things, the schema specifies the namespace into which
 | 
						|
an API should be injected, what permissions (if any) are required to
 | 
						|
use it, and in which contexts (e.g., extension pages, content scripts, etc)
 | 
						|
it should be available.  The WebExtensions framework reads this schema
 | 
						|
and takes care of injecting the right objects into each extension
 | 
						|
Javascript environment.
 | 
						|
 | 
						|
API schemas are written in JSON and are based on
 | 
						|
`JSON Schema <http://json-schema.org/>`_ with some extensions to describe
 | 
						|
API functions and events.
 | 
						|
The next section describes the format of the schema in detail.
 | 
						|
 | 
						|
The ExtensionAPI class
 | 
						|
----------------------
 | 
						|
Every WebExtensions API is represented by an instance of the Javascript
 | 
						|
`ExtensionAPI <reference.html#extensionapi-class>`_ class.
 | 
						|
An instance of its API class is created every time an extension that has
 | 
						|
access to the API is enabled.  Instances of this class contain the
 | 
						|
implementations of functions and events that are exposed to extensions,
 | 
						|
and they also contain code for handling manifest keys as well as other
 | 
						|
part of the extension lifecycle (e.g., updates, uninstalls, etc.)
 | 
						|
The details of this class are covered in a subsequent section, for now the
 | 
						|
important point is that this class contains all the actual code that
 | 
						|
backs a particular WebExtensions API.
 | 
						|
 | 
						|
Built-in versus Experimental APIs
 | 
						|
---------------------------------
 | 
						|
A WebExtensions API can be built directly into the browser or it can be
 | 
						|
contained in a special type of extension called a privileged extension
 | 
						|
that defines a WebExtensions Experiment (i.e. experimental APIs).
 | 
						|
The API schema and the ExtensionAPI class are written in the same way
 | 
						|
regardless of how the API will be delivered, the rest of this section
 | 
						|
explains how to package a new API using these methods.
 | 
						|
 | 
						|
Adding a built-in API
 | 
						|
---------------------
 | 
						|
Built-in WebExtensions APIs are loaded lazily.  That is, the schema and
 | 
						|
accompanying code are not actually loaded and interpreted until an
 | 
						|
extension that uses the API is activated.
 | 
						|
To actually register the API with the WebExtensions framework, an entry
 | 
						|
must be added to the list of WebExtensions modules in one of the following
 | 
						|
files:
 | 
						|
 | 
						|
- ``toolkit/components/extensions/ext-toolkit.json``
 | 
						|
- ``browser/components/extensions/ext-browser.json``
 | 
						|
- ``mobile/android/components/extensions/ext-android.json``
 | 
						|
 | 
						|
Here is a sample fragment for a new API:
 | 
						|
 | 
						|
.. code-block:: js
 | 
						|
 | 
						|
    "myapi": {
 | 
						|
      "schema": "chrome://extensions/content/schemas/myapi.json",
 | 
						|
      "url": "chrome://extensions/content/ext-myapi.js",
 | 
						|
      "paths": [
 | 
						|
        ["myapi"],
 | 
						|
        ["anothernamespace", "subproperty"]
 | 
						|
      ],
 | 
						|
      "scopes": ["addon_parent"],
 | 
						|
      "permissions": ["myapi"],
 | 
						|
      "manifest": ["myapi_key"],
 | 
						|
      "events": ["update", "uninstall"]
 | 
						|
    }
 | 
						|
 | 
						|
The ``schema`` and ``url`` properties are simply URLs for the API schema
 | 
						|
and the code implementing the API.  The ``chrome:`` URLs in the example above
 | 
						|
are typically created by adding entries to ``jar.mn`` in the mozilla-central
 | 
						|
directory where the API implementation is kept.  The standard locations for
 | 
						|
API implementations are:
 | 
						|
 | 
						|
- ``toolkit/components/extensions``: This is where APIs that work in both
 | 
						|
  the desktop and mobile versions of Firefox (as well as potentially any
 | 
						|
  other applications built on Gecko) should go
 | 
						|
- ``browser/components/extensions``: APIs that are only supported on
 | 
						|
  Firefox for the desktop.
 | 
						|
- ``mobile/android/components/extensions``: APIs that are only supported
 | 
						|
  on Firefox for Android.
 | 
						|
 | 
						|
Within the appropriate extensions directory, the convention is that the
 | 
						|
API schema is in a file called ``schemas/name.json`` (where *name* is
 | 
						|
the name of the API, typically the same as its namespace if it has
 | 
						|
Javascript visible features).  The code for the ExtensionAPI class is put
 | 
						|
in a file called ``ext-name.js``.  If the API has code that runs in a
 | 
						|
child process, that is conventionally put in a file called ``ext-c-name.js``.
 | 
						|
 | 
						|
The remaining properties specify when an API should be loaded.
 | 
						|
The ``paths``, ``scopes``, and ``permissions`` properties together
 | 
						|
cause an API to be loaded when Javascript code in an extension references
 | 
						|
something beneath the ``browser`` global object that is part of the API.
 | 
						|
The ``paths`` property is an array of paths where each individual path is
 | 
						|
also an array of property names.  In the example above, the sample API will
 | 
						|
be loaded if an extension references either ``browser.myapi`` or
 | 
						|
``browser.anothernamespace.subproperty``.
 | 
						|
 | 
						|
A reference to a property beneath ``browser`` only causes the API to be
 | 
						|
loaded if it occurs within a scope listed in the ``scopes`` property.
 | 
						|
A scope corresponds to the combination of a Javascript environment
 | 
						|
(e.g., extension pages, content scripts, etc) and the process in which the
 | 
						|
API code should run (which is either the main/parent process, or a
 | 
						|
content/child process).
 | 
						|
Valid ``scopes`` are:
 | 
						|
 | 
						|
- ``"addon_parent"``, ``"addon_child``: Extension pages
 | 
						|
 | 
						|
- ``"content_parent"``, ``"content_child``: Content scripts
 | 
						|
 | 
						|
- ``"devtools_parent"``, ``"devtools_child"``: Devtools pages
 | 
						|
 | 
						|
The distinction between the ``_parent`` and ``_child`` scopes will be
 | 
						|
explained in further detail in following sections.
 | 
						|
 | 
						|
A reference to a property only causes the API to be loaded if the
 | 
						|
extension referencing the property also has all the permissions listed
 | 
						|
in the ``permissions`` property.
 | 
						|
 | 
						|
A WebExtensions API that is controlled by a manifest key can also be loaded
 | 
						|
when an extension that includes the relevant manifest key is activated.
 | 
						|
This is specified by the ``manifest`` property, which lists any manifest keys
 | 
						|
that should cause the API to be loaded.
 | 
						|
 | 
						|
Finally, APIs can be loaded based on other events in the WebExtension
 | 
						|
lifecycle.  These are listed in the ``events`` property and described in
 | 
						|
more detail in :ref:`lifecycle`.
 | 
						|
 | 
						|
Adding Experimental APIs in Privileged Extensions
 | 
						|
-------------------------------------------------
 | 
						|
 | 
						|
A new API may also be implemented within a privileged extension. An API
 | 
						|
implemented this way is called a WebExtensions Experiment (or simply an
 | 
						|
Experimental API).  Experiments can be useful when actively developing a
 | 
						|
new API, as they do not require building Firefox locally. These extensions
 | 
						|
may be installed temporarily via ``about:debugging`` or, on browser that
 | 
						|
support it (current Nightly and Developer Edition), by setting the preference
 | 
						|
``xpinstall.signatures.required`` to ``false``.  You may also set the
 | 
						|
preference ``extensions.experiments.enabled`` to ``true`` to install the
 | 
						|
addon normally and test across restart.
 | 
						|
 | 
						|
.. note::
 | 
						|
   Out-of-tree privileged extensions cannot be signed by addons.mozilla.org.
 | 
						|
   A different pipeline is used to sign them with a privileged certificate.
 | 
						|
   You'll find more information in the `xpi-manifest repository on GitHub <https://github.com/mozilla-extensions/xpi-manifest>`_.
 | 
						|
 | 
						|
Experimental APIs have a few limitations compared with built-in APIs:
 | 
						|
 | 
						|
- Experimental APIs can (currently) only be exposed to extension pages,
 | 
						|
  not to devtools pages or to content scripts.
 | 
						|
- Experimental APIs cannot handle manifest keys (since the extension manifest
 | 
						|
  needs to be parsed and validated before experimental APIs are loaded).
 | 
						|
- Experimental APIs cannot use the static ``"update"`` and ``"uninstall"``
 | 
						|
  lifecycle events (since in general those may occur when an affected
 | 
						|
  extension is not active or installed).
 | 
						|
 | 
						|
Experimental APIs are declared in the ``experiment_apis`` property in a
 | 
						|
WebExtension's ``manifest.json`` file.  For example:
 | 
						|
 | 
						|
.. code-block:: js
 | 
						|
 | 
						|
  {
 | 
						|
    "manifest_version": 2,
 | 
						|
    "name": "Extension containing an experimental API",
 | 
						|
    "experiment_apis": {
 | 
						|
      "apiname": {
 | 
						|
        "schema": "schema.json",
 | 
						|
        "parent": {
 | 
						|
          "scopes": ["addon_parent"],
 | 
						|
          "paths": [["myapi"]],
 | 
						|
          "script": "implementation.js"
 | 
						|
        },
 | 
						|
 | 
						|
        "child": {
 | 
						|
          "scopes": ["addon_child"],
 | 
						|
          "paths": [["myapi"]],
 | 
						|
          "script": "child-implementation.js"
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
This is essentially the same information required for built-in APIs,
 | 
						|
just organized differently.  The ``schema`` property is a relative path
 | 
						|
to a file inside the extension containing the API schema.  The actual
 | 
						|
implementation details for the parent process and for child processes
 | 
						|
are defined in the ``parent`` and ``child`` properties of the API
 | 
						|
definition respectively.  Inside these sections, the ``scope`` and ``paths``
 | 
						|
properties have the same meaning as those properties in the definition
 | 
						|
of a built-in API (though see the note above about limitations; the
 | 
						|
only currently valid values for ``scope`` are ``"addon_parent"`` and
 | 
						|
``"addon_child"``).  The ``script`` property is a relative path to a file
 | 
						|
inside the extension containing the implementation of the API.
 | 
						|
 | 
						|
The extension that includes an experiment defined in this way automatically
 | 
						|
gets access to the experimental API.  An extension may also use an
 | 
						|
experimental API implemented in a different extension by including the
 | 
						|
string ``experiments.name`` in the ``permissions``` property in its
 | 
						|
``manifest.json`` file.  In this case, the string name must be replace by
 | 
						|
the name of the API from the extension that defined it (e.g., ``apiname``
 | 
						|
in the example above.
 | 
						|
 | 
						|
Globals available in the API scripts global
 | 
						|
-------------------------------------------
 | 
						|
 | 
						|
The API scripts aren't loaded as an JSM and so:
 | 
						|
 | 
						|
- they are not fully isolated from each other (and they are going to be
 | 
						|
  lazy loaded when the extension does use them for the first time) and
 | 
						|
  be executed in a per-process shared global scope)
 | 
						|
- the experimental APIs embedded in privileged extensions are executed
 | 
						|
  in a per-extension global (separate from the one used for the built-in APIs)
 | 
						|
 | 
						|
The global scope where the API scripts are executed is pre-populated with
 | 
						|
some useful globals:
 | 
						|
 | 
						|
- ``AppConstants``
 | 
						|
- ``console``
 | 
						|
- ``CC``, ``Ci``, ``Cr`` and ``Cu``
 | 
						|
- ``ChromeWorker``
 | 
						|
- ``extensions``, ``ExtensionAPI``, ``ExtensionCommon`` and ``ExtensionUtils``
 | 
						|
- ``global``
 | 
						|
- ``MatchGlob``, ``MatchPattern`` and ``MatchPatternSet``
 | 
						|
- ``Services``
 | 
						|
- ``StructuredCloneHolder``
 | 
						|
- ``XPCOMUtils``
 | 
						|
 | 
						|
For a more complete and updated list of the globals available by default in
 | 
						|
all API scripts look to the following source:
 | 
						|
 | 
						|
- `SchemaAPIManager _createExtGlobal method <https://searchfox.org/mozilla-central/search?q=symbol:SchemaAPIManager%23_createExtGlobal&redirect=false>`_
 | 
						|
- Only available in the parent Firefox process:
 | 
						|
  `toolkit/components/extensions/parent/ext-toolkit.js <https://searchfox.org/mozilla-central/source/toolkit/components/extensions/parent/ext-toolkit.js>`_
 | 
						|
- Only available in the child Firefox process:
 | 
						|
  `toolkit/components/extensions/child/ext-toolkit.js <https://searchfox.org/mozilla-central/source/toolkit/components/extensions/child/ext-toolkit.js>`_
 | 
						|
- Only available in the Desktop builds:
 | 
						|
  `browser/components/extensions/parent/ext-browser.js <https://searchfox.org/mozilla-central/source/browser/components/extensions/parent/ext-browser.js>`_
 | 
						|
- Only available in the Android builds:
 | 
						|
  `mobile/android/components/extensions/ext-android.js <https://searchfox.org/mozilla-central/source/mobile/android/components/extensions/ext-android.js>`_
 | 
						|
 | 
						|
.. warning::
 | 
						|
   The extension API authors should never redefine these globals to avoid introducing potential
 | 
						|
   conflicts between API scripts (e.g. see `Bug 1697404 comment 3 <https://bugzilla.mozilla.org/show_bug.cgi?id=1697404#c3>`_
 | 
						|
   and `Bug 1697404 comment 4 <https://bugzilla.mozilla.org/show_bug.cgi?id=1697404#c4>`_).
 | 
						|
 | 
						|
WebIDL Bindings
 | 
						|
---------------
 | 
						|
 | 
						|
In ``manifest_version: 3`` the extension will be able to declare a background service worker
 | 
						|
instead of a background page, and the existing WebExtensions API bindings can't be injected into this
 | 
						|
new extension global, because it lives off the main thread.
 | 
						|
 | 
						|
To expose WebExtensions API bindings to the WebExtensions ``background.service_worker`` global
 | 
						|
we are in the process of generating new WebIDL bindings for the WebExtensions API.
 | 
						|
 | 
						|
An high level view of the architecture and a more in depth details about the architecture process
 | 
						|
to create or modify WebIDL bindings for the WebExtensions API can be found here:
 | 
						|
 | 
						|
.. toctree::
 | 
						|
   :maxdepth: 2
 | 
						|
 | 
						|
   webidl_bindings
 |