Hack 88. Make, Bundle, and Publish an XPI


Create an XPI installer for your extension and
publish it for others to discover and use.
If you've stepped through the hacks in this chapter
in order, or done any serious XUL experimentation, then
you're ready to consider releasing that XML as an
extension. You have your content, locale, and skin files in place as
a package, written and tested. All that is left is to bundle it up
and release it. The best method to bundle it up is to use
Mozilla's Cross-Platform Install (XPI) technology.
XPI files are compressed files that can be put together using
standard zip tools. Firefox can load and install
XPI files.
This hack explores the structure of the XPI formatin
particular, which files go where in the compressed archive.
We'll also dissect the
install.rdf install file to ensure that
installation is successful. Finally, to ensure your extension is not
hidden away, we'll discuss the best ways to
distribute it for people to use.
8.6.1. Making a Firefox XPI File
Once created, the XPI file
has a rigid structure for Firefox extensions, more so than it does
for a Mozilla Application Suite extension. Most extensions just
install chrome (i.e., a JAR file or directory with XUL, JavaScript,
CSS, and locale files). However, there are optional folders for
distributing other files, including XPCOM components [Hack #82], command-line handlers,
preference files, and icons. Here's an XPI directory
breakdown:
chromedit.xpi
chrome
chromedit.jar
components
defaults
ce-main.xpm
ce-main.ico
userChrome-example.css
userContent-example.css
install.rdf
Each of the folderschrome/,
components/, and
defaults/is optional. The
install.rdf file, however, is compulsory.
chromEdit does not have any XPCOM components. To
view this example on your computer, save the
chromedit.xpi file locally (by right-clicking
the download link) from http://cdn.mozdev.org/chromedit/ and unzip
it.
To compress the JAR and XPI files, you can use any standard ZIP
program, such as WinZip on Windows. This is something you will be
doing frequently during the development cycle, especially if you are
using a JAR file. Instead of constantly dealing with GUI ZIP programs
or manually working with ZIP files, your best bet is to automate the
process.
Here is a simple shell script for compressing the JAR file and the
XPI file:
#!/bin/sh
echo "building chromedit ..."; # cleanup any old stuff
rm chromedit.xpi;
rm chrome/chromedit.jar;
echo "JAR file ..."; # make and move the JAR
zip -r0 chromedit.jar content locale skin
mv chromedit.jar chrome;
echo "XPI file ..."; # make the XPI
zip -r9 chromedit.xpi install.rdf defaults chrome
echo "Extension build finished.";
This script uses the standard Info-ZIP zip
program, which can also be found on Windows as part of the Cygwin
package. The ZIP flags used here are -r to recurse
into subfolders, -0 to store only (no
compression), and -9 for maximum compression.
8.6.2. Understanding install.rdf
The core install file for a Firefox extension is called
install.rdf.
This file lives at the root of the XPI file. During install, if
Firefox detects this file, it reads in the metadata to add the
extension. Here's a sample install file for the
chromEdit extension:
<?xml version="1.0"?>
<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>{2cf89d59-8610-4053-b207-85c6a128f65d}</em:id>
<em:version>0.1.1.1</em:version>
<!-- Firefox -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>1.0+</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>ChromEdit</em:name>
<em:description>A Simple User Profile File Editor</em:description>
<em:creator>Chris Neale</em:creator>
<em:contributor>Andrew Wooldridge</em:contributor>
<em:contributor>Brian King</em:contributor>
<!-- more ... -->
<em:homepageURL>http://cdn.mozdev.org/chromedit/</em:homepageURL>
<em:updateURL>http://cdn.mozdev.org/chromedit/update.rdf</em:updateURL>
<em:iconURL>chrome://chromedit/skin/images/ce.x32.png</em:iconURL>
<em:file>
<Description about="urn:mozilla:extension:file:chromedit.jar">
<em:package>content/</em:package>
<em:skin>skin/classic/</em:skin>
<em:locale>locale/en-US/</em:locale>
<em:locale>locale/de-DE/</em:locale>
<em:locale>locale/it-IT/</em:locale>
<em:locale>locale/nl-NL/</em:locale>
<em:locale>locale/pl-PL/</em:locale>
</Description>
</em:file>
</Description>
</RDF>
Every extension needs its own unique ID in Firefox, and the format
this takes is a UUID. A
UUID
is a registration code that can be generated in a number of ways,
including on Windows using guidgen.exe, on Unix
using uuidgen, or using IRC by connecting to
Table 8-2 shows all possible tags. Each needs to be
prefixed with the Extension Manager namespace
(em:).
Tag | Description |
---|---|
Name | UI friendly name |
Description | One-liner about the extension |
Creator | Individual or company's name that wrote the extension |
Contributor | Other authors (can be more than one) |
HomepageURL | URL of extension homepage |
UpdateURL | URL of update file |
AboutURL | URL (usually chrome:) to about dialog for the extension |
IconURL | URL to image shown in the Extension Manager |
File | Pointers to packages, skins, and locales that this extension registers |
Finally, the file states the ordinary packages, skins, and locales
that this extension registers. Relative JAR file paths are used to
point to the locations of the package, skin and locale
contents.rdf files.
8.6.3. The First Big Release
So, now you have reached the point where you have the XPI installer
file or files, and all that's left is for people to
find out about it and download/install it. This section covers the
two ways you can do this: either hosting it on
Mozilla's update service or hosting it on your own
servers with helper scripts to get you going.
8.6.3.1 Using Mozilla Update
At the time of writing, the process of getting your
extension listed is not mature
and can be frustrating. This is because all requests for listings and
updates must be done through Mozilla's bug tracking
system (http://bugzilla.mozilla.org). The admin
interface, which will eventually be part of the site and easily
accessible, is not up and running yet. The plan is that extension
authors, once logged in, will have complete control over their
distributions: the uploading of new versions, editing of the
description, and moderation of user comments. The download counter is
a good measure of how popular your extension is.
8.6.3.2 DIY publishing
There is an alternative to using Mozilla Update, and that is to host
the XPI on the server of your choice. The most straightforward
approach is to just upload the file and link directly to it from an
HTML page. However, there are some helper JavaScript install scripts
that you can use to assist installation. Here is a very basic
one:
function install(aXpi) {
if (!InstallTrigger || !InstallTrigger.updateEnabled( ))
return false;
else
return InstallTrigger.install(aXpi);
}
It can be called like this in the HTML:
<a href="#" onclick="install('http://myhost.com/extension/extension.xpi')">
The install function checks that software
installation is enabled (Tools
Features
software") and, if so, proceeds with the
installation. Note the use of the global
InstallTrigger object. You can find more
information about it at http://www.xulplanet.com/references/elemref/ref_InstallTriggerl.
Make sure the web server is set up correctly [Hack #27] .
|
<user profile dir>/extensions/<UUID of extension>/
|
8.6.4. Distribute Software Updates
This section covers
extension
updates. Firefox has a built-in update mechanism [Hack #13] . Earlier in this hack, in
Section 8.6.2,
you might have noticed this entry in that file:
<em:updateURL>http://cdn.mozdev.org/chromedit/update.rdf</em:updateURL>
This entry tells Firefox where to look for the update file that will
contain version information and links to updates for the extension.
The following example shows the file for the jsLib extension
(http://jslib.mozdev.org/updateLite.rdf):
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<RDF:Description about="urn:mozilla:extension:{DF8E5247-8E0A-4de6-
B393-0735A39DFD80}">
<em:updates>
<RDF:Seq>
<RDF:li resource="urn:mozilla:extension:
{DF8E5247-8E0A-4de6-B393-0735A39DFD80}:0.1.214"/>
</RDF:Seq>
</em:updates>
<em:version>0.1.214</em:version>
<em:updateLink>http://download.mozdev.org/jslib/xpi/jslib_current_lite.xpi<
/em:updateLink>
</RDF:Description>
<RDF:Description about="urn:mozilla:extension:{DF8E5247-8E0A-4de6-B393-
0735A39DFD80}
:0.1.214">
<em:version>0.1.214</em:version>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>1.0</em:maxVersion>
<em:updateLink>http://download.mozdev.org/jslib/xpi/
jslib_current_lite.xpi</em:updateLink>
</Description>
</em:targetApplication>
</RDF:Description>
</RDF:RDF>
|
Again, the server must be set up with the right types [Hack #27] . This example shows two
necessary description blocks. The first one covers the extension
itself, telling Firefox that an update is available for an extension
of a given ID. The new version number of that extension is also
listed, along with the location of the new extension.
The second description block details the target application that the
extension applies to. In this case, it is Firefox; so the Firefox
em:id is given, plus the minimum and maximum
version of Firefox that this update applies to. When Firefox checks
for updates, it compares the version already installed with the
version in the update file. If a later version is found, the user is
given the option to install the newer version.
Brian King