Shipping a plugin as a Toolkit bundle

One of the new features that is available in Firefox 1.5 is the ability to place browser plugins in a Toolkit bundle.

Historically, most people have chosen to use an install.js script to install a plugin. When this method is used, you can choose to either place the plugin into the plugins directory, or place it into your own directory and modify the Windows registry to let Firefox know where to find the plugin. The downside to this method is that once the plugin is installed, it might be difficult for users to upgrade, uninstall, or disable the plugin. As of Firefox 3 (and any Gecko 1.9 based application) the use of install.js scripts is no longer supported and plugins must either be shipped as an executable installer or in a bundle as described here.

Bundle structure

Toolkit bundles can be used for all add-ons including extensions, themes and plugins. Plugin packages should only need to package a small set of files in the following structure in the xpi file:

install.rdf
plugins/
    pluginlib.dll
    plugintypes.xpt

The install.rdf file contains an install manifest that describes the plugin to the user. The library and scripting interfaces are held in the plugins directory.

Platform-specific files

Gecko 1.9.2 (Firefox 3.6) and earlier

Prior to Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1), it was possible to package multiple plugin libraries for different operating systems into a single xpi bundle. In the XPI you can use the following structure:

platform/
    Linux_x86-gcc3/
        plugins/
            libplugin.so
    Darwin_ppc-gcc3/
        plugins/
            libplugin.dylib

More specific information can be found in the platform-specific subdirectories documentation.

Gecko 2.0 (Firefox 4) and later

Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) removed support for platform-specific subdirectories. Instead, you need to place the different plugin libraries into the plugins directory.

For example:

plugins/
    libplugin.so
    libplugin.dylib

Install Manifest

The install manifest describes the plugin to the user. For a plugin the manifest only needs to be very simple:

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  <Description about="urn:mozilla:install-manifest">
    <em:id>mypluginid@myplugin.com</em:id>
    <em:name>My Plugin</em:name>
    <em:version>1.0</em:version>
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>1.5</em:minVersion>
        <em:maxVersion>4.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
    <em:unpack>true</em:unpack>
  </Description>
</RDF>

This contains 5 required pieces of information.

  1. Every add-on must have a unique id. This can be in a guid form but the simpler email form is preferred now. You should aim to use a domain-name that you own and then your own unique short-name for the plugin before the @.
  2. The plugin must have a name to identify the plugin to the user in the list of add-ons.
  3. The version is fairly self-descriptive, it must be a toolkit version format.
  4. The target application block says which versions of an application the plugin is compatible with. It includes the application ID and the minimum and maximum version of the application that the plugin works with. There can be multiple targetApplication blocks listed.
  5. The unpack property is necessary to tell applications using newer versions of Gecko to unpack the plugin because DLLs can't be loaded from XPI files.

Providing updates

When plugins are packaged in this way they can make use of the built in add-on update system. This allows a remote update file to be read periodically and an updated version of the plugin offered to the user or to mark the plugin as compatible with a wider range of applications.

This is performed by including an updateURL in the install manifest. This should point to an update.rdf file on the internet which will include the updated versions and version information for the plugin.