Using XPInstall to Install Plugins

Parts of this page show the use of the XPInstall API. The majority of this API is now deprecated and as of Gecko 1.9 no longer available. Extension, Theme, and plug-in developers must switch away from install.js based packages to the new packaging scheme with an install.rdf manifest. In particular plugin developers should see how to package a plugin as an extension.

XPInstall is a JavaScript-based installer technology that works across all the platforms that Mozilla and Netscape browsers based on Mozilla (such as Netscape 7) are deployed. It can be a way to ensure a smooth user-experience when obtaining plugins, without obliging the user to exit the browsing environment to launch a binary installer (the classic setup.exe experience on Windows) or obliging the user to restart their browser. For plugin vendors who have already written a native code (e.g. EXE) installer, XPInstall can wrap this native installer and run it so that the user never has to leave the browsing environment and click on the EXE to run it. This article presents a guideline for improving the plugin installation experience for Netscape Gecko browsers using XPInstall.

A Definition of Terms

XPInstall is an installer technology, and the name itself stands for "Cross Platform Install" (hence "XP" -- an abbreviation for "Cross Platform"). An XPInstall package is usually called an XPI package for short (and often pronounced "zippy"). This article is about how you can use XPInstall to install plugins to the browsers that support XPInstall.

An XPI Package is in fact a ZIP file with the XPI file extension (e.g. myPluginInstaller.xpi), and can be created on Windows by utilities such as WinZip. XPI Packages, like ZIP files, "contain" other files, typically:

  • The software component to be installed. In our case, this is the plugin software.
  • A JavaScript file called install.js, which is the install logic that drives the installation. This includes instructions on where to install the software, and what messages to feed to the user.

You can create an XPInstall file by first zipping all the items you want installed with WinZip (create a ZIP archive) and then renaming it with the XPI file extension instead of the ZIP file extension.

Unlike native code installers (for example, files called setup.exe), the programming language for install operations in XPI is JavaScript. Since the file format that contains the software and the install.js JavaScript file is a cross-platform file (Zip) and since JavaScript is understood by Mozilla browsers on all platforms, often one single XPI package can be deployed on all platforms. This is, in fact, how skins and themes are installed to Mozilla browsers, changing their look and feel. This article focuses on how to install plugins.

Which Browsers Support XPInstall?

Currently, all Mozilla browsers released by mozilla.org support XPInstall, and a family of browsers based on Mozilla code support XPInstall. In particular, this includes:

  • Recent Netscape browsers such as Netscape 6.2.x and Netscape 7.0, which are both based on Netscape Gecko, which is at the core of the Mozilla browser
  • Recent beta-only versions of the AOL software based on Netscape Gecko, the layout engine of the Mozilla project.

Caveats:

  • AOL Time Warner's CompuServe browser, also based on Netscape Gecko, does not support XPInstall.
  • Netscape Communicator 4.x does not support XPInstall.

What Does a Plugin Consist Of?

Plugins can consist of the following types of files, all of which can be installed via an XPI Package:

  • Shared Libraries (i.e. on Windows, these are DLLs, on Unix these are *.so files). These files are native code files made with the Netscape Plugin API.
  • If the plugin is scriptable, then it will also consist of an XPT file. Examples would be Flash 6r47 on Windows, which consists of a DLL (called npswf32.dll) and an XPT file for scriptability (called flashplayer.xpt). If you are developing a plugin and wish to make it scriptable, read the relevant portions of the Plugin API.
  • Additional software. Many plugins are part of additional software for media types. For example, RealPlayer on Windows consists of a plugin DLL, but also the RealPlayer application (EXE) which the plugin DLL is a subset of. In this case, the plugin is the part of the software package that is browser-specific, as a mechanism to give the application additional "hooks" into the browser.

XPInstall can be used to install any combination of these files on an end-user's machine. For those familiar with Netscape Communicator 4.x's SmartUpdate technology, this will be a familiar idea.

A Brief History of Netscape Installer Technologies

This section is relevant if you are familiar with Netscape Communicator 4.x's SmartUpdate installer technology. The use of JavaScript as the install logic is not unprecedented in Netscape browsers. Netscape Communicator 4.x uses the notion of SmartUpdate to install software, particularly plugins and Java applets to be run locally. SmartUpdate is not supported by Mozilla browsers (and Netscape/AOL browsers based on Mozilla such as Netscape 7), but because of the similarity between the two installer technologies, it is easy to convert your SmartUpdate files to XPInstall files. SmartUpdate involves a digitally signed JAR file which contained the software components to be installed as well as a JavaScript install.js file (called the install script) as the installer logic. Downloads and installs would be initiated with a security dialog box naming the certificate authority and the signer. Often, the SmartUpdate download was triggered via the pluginurl attribute of the embed tag:

<embed type="application/x-randomtype" src="myfile.typ" width="50" height="50"
pluginurl="http://mytypecompany.xyz/jarpacks/mytypeplugin.jar"></embed>

In the example above, the pluginurl attribute points to the signed JAR file, which Netscape Communicator 4.x would then download (subject to the security dialog boxes) if the plugin was not located on the user's machine. SmartUpdate differs from XPInstall in that:

  • XPInstall uses ZIP files named XPI files (*.xpi) and SmartUpdate uses JAR files (*.jar)
  • Unlike a SmartUpdate JAR file, XPI Packages do not have to be digitally signed with a code-signing certificate.
  • XPI Packages make use of different APIs from within install.js, although the concept is the same.

XPInstall for Mozilla-based browsers is analogous to SmartUpdate in Netscape Communicator 4.x browsers. Porting SmartUpdate deployments to XPInstall is trivial after gaining some familiarity with the new XPInstall API.

XPInstall provides a cohesive API to accomplish rapid installation and setup of plugin software for end-users. The benefit of using XPInstall is to provide a streamlined installation mechanism. This section discusses what an ideal XPInstall Package will do, as well as points out some of the JavaScript API calls that you will make to accomplish these install tasks. An ideal XPI Package will:

  1. Install to the current browser that is initiating the XPInstall installation via HTML or triggering an XPInstall installation via a Trigger Script. We will use the term current browser to refer to the browser that initiates the XPInstall download by visiting a site which requires a plugin that the current browser can not find locally. This step will involve the use of the initInstall API call to start everything off, and also the getFolder API call, which helps to locate the current browser's plugin directory.
  2. Install the plugin software to another location on the user's hard disk, so that other Mozilla-based browsers that the user may install later can find the plugin (the browser specific components) and pick it up. The goal is to ensure that future Netscape Gecko browsers that the user may install later can benefit from the installation that the user initiated with the current browser. An example might be that the current browser is Netscape 7, but later, the user downloads a beta of the AOL software using Netscape Gecko. Rather than re-initiate the download of the plugin with the yet another browser, the second Netscape Gecko browser can detect that an installation has already occurred. This discovery mechanism hinges on making the secondary install location available from looking at a common repository of metadata. On Windows, this is the Windows System Registry. Once again, this step involves calls to getFolder to locate a "well known" directory in which to install to as a secondary install location.
  3. On Windows: write Windows Registry keys that Netscape Gecko browsers (that get installed after the current browser) can parse to discover where the plugin is installed on the machine. In particular, the Windows Registry keys should point to the secondary install location so that future Netscape Gecko browsers can find and add to their list of available plugin locations. The exact format of these registry keys and how they should be written is covered in the section on the first install problem. To actually create and write keys to the Windows System Registry, you'll use the functions of the WinReg object.
  4. Ensure that the plugin that has just been installed is refreshed by correctly invoking the refreshPlugins API. By refreshing your plugin, you're ensuring that the plugin is available for use immediately, without obliging the user to restart their browser. This is one of the chief advantages of a smooth XPInstall experience.

The First Install Problem

The First Install Problem refers to the conditions arising when a plugin arrives on a user's machine before a browser arrives. The recommended install process addresses this issue, which is to install to a secondary location after installing to the current browser. In a nutshell, the first install problem can be summed up by the question: how can a browser which is installed on a user's machine after a given plugin has already been installed by the user benefit from the existing installation rather than download the same plugin again? In order to address this issue, plugin vendors are encouraged to:

  • Install the plugin software components for the browser (e.g. DLLs on Windows, and XPT files if applicable) to a secondary location, in addition to that of the plugins directory of the current browser.
  • Write keys in the Windows registry which store information about this secondary location, in particular the Plugin Path and the XPT Path (if applicable) so that Netscape Gecko browsers can pick up the plugin from the secondary location if they are installed after the plugin is (and thus, if a particular Netscape Gecko browser follows or replaces the current browser). The keys to write and the information they should contain is discussed in detail in the specification posted on mozilla.org. There is also a sample registry entry created by an imaginary company that is illustrative of what is discussed in the specification for these registry keys.
  • On Windows, the Windows Registry keys mentioned above follow a nomenclature using the concept of a Plugin Identifier as the name of the key under the MozillaPlugins subkey. The Plugin Identifier (or PLID) is a useful concept that is also applicable when initializing the installation via the initInstall API.

A Breakdown of the APIs Used

The recommended plugin installation process makes use of the XPInstall APIs to install to the current browser's Plugins directory, install to a secondary location, and to write to the Windows System Registry to disclose this secondary location. This section traces some of the XPInstall APIs that can do this. A complete template of an XPI Package is also presented in this section. Not all the work needs to be done in JavaScript -- if you have a native installer (EXE) that recognizes Netscape Gecko browsers, and you merely wish to wrap the EXE installer in an XPI Package for a streamlined delivery to the client, you can easily do so. This section refers extensively to the XPInstall API Documentation.

Initializing Installation with Plugin Identifier

All XPInstall installations are initiated with the initInstall method of the Install Object. Since the Install Object is available to the install script, it need not be mentioned in the install script (e.g. there is no need to invoke Install.initInstall; simply invoking initInstall will suffice). The initInstall method is polymorphic, but here is a recommended invocation mechanism:

initInstall("My Plugin Software", "@myplugin.com/MyPlugin,version=2.5", "2.5.0.0");

In the code snippet above, the initInstall method is invoked with three parameters:

  • A String for the name of the application
  • A String signifying the Plugin Identifier associated with the plugin. This value is actually entered in the Client Version Registry upon installation, a Mozilla-browser file that stores metadata about the software that has just been installed. This value can be queried via web-page delivered JavaScript, and is useful for initiating XPInstall downloads via Trigger Scripts. You can determine the version of the software that has been installed, and determine whether to update it, all via JavaScript in a web-page.
  • A String representing the four digit version of the software.

Caveat: Certain versions of Mozilla-based browsers (such as Netscape 6.x) treat the use of the equals character ("=") as an illegal token and thus do not allow invocation of initInstall with strings containing "=". A workaround to this would be to detect if initInstall has failed, and then invoke it again without the "=" string. Here is an example:

var PLID = "MyPlugin.plug/version=6.5";
err = initInstall(SOFTWARE_NAME, PLID, VERSION);

if (err != 0)
{
	// install may have failed because of N6 and =
	// replace PLID with a simple string
	err = initInstall(SOFTWARE_NAME, "MyPluginString", VERSION);
	if (err != 0)
		cancelInstall(err);
}

Note that above, the PLID contains an "=" and in case the XPI package is running on browsers that treat "=" as an illegal token, the workaround is to handle the error and invoke initInstall again.

Using XPInstall to Run an EXE (Native Code) Installer

If you wish to run a native installer (EXE) to install plugin software, but wish to make the delivery of this native installer streamlined and within the browser's process, then you ought to consider wrapping it in an XPI Package. From JavaScript, you can call XPInstall's execute method of the Install Object to execute the binary. You can also call the execute method of the File object if you wish to actually install the file you are executing, rather than have it deleted. You can pass command line parameters to the executable. An example of calling the execute method from the Install Object on an executable that has a temporary life span (and is not needed after one execution) is:

// Initialize the installation ....

// initInstall(..... ) has already been called

// Using the Install Object's execute method to block on a native installer

execute("setup.exe", "-s", true);	

// In the above sample, assume that running "setup -s" from the
// Command Prompt runs the setup executable, and that  "-s" is some
// invocation parameter defined by the setup.exe file, perhaps to force
// the installer to run silently.  We are passing "-s" to the setup file.
// By passing 'true' we are telling the Install Script to block
// on the execution of the installable, and do it synchronously

// Must call performInstall to make it all happen...

err = getLastError();
if (!err)
   performInstall();
else
  cancelInstall(err);

Installing Plugin Files To the Current Browser

Installing to the current browser is the task that is the most important for the XPI Package to succeed in. Here is a code snippet that accomplishes this:

// Name of the files to be installed
var PLUGIN_FILE    = "NPMyPlugin.dll";
var COMPONENT_FILE = "NPMyPluginScriptablePeer.xpt";

// invoke initInstall to start the installation

....

var pluginFolder = getFolder("Plugins");

// verify disk space is appropriate

....

err = addFile("@myplugin.com/MyPlugin,version=2.5.0.0",
                     "2.5.0.0", PLUGIN_FILE, pluginsFolder, null);
    if (err != 0)
    {
	//alert("Installation of MyPlugin plug-in failed. Error code "+err);
	logComment("adding file "+PLUGIN_FILE+" failed. Errror conde: " + err);
	return err;
    }

err = addFile(null, CULT_VERSION, COMPONENT_FILE, componentsFolder, null);
    if (err != 0)
    {
	alert("Installation of MyPlugin component failed. Error code "+err);
	logComment("adding file "+COMPONENT_FILE+" failed. Error conde: " + err);
	return err;
    }

Installing to a Secondary Location

For the purposes of solving the First Install Problem, it is necessary to install to a secondary location to ensure discoverability of the plugin by other Netscape Gecko browser in addition to the current browser. A good choice for this secondary location might be the Windows directory on Windows machines. Caveat: Because of possible administrator issues, handle errors carefully!

// Get the Windows System directory e.g. C:\WINNT\system32\ directory

var winDirectory = getFolder("Win System");

// Create the Folder C:\WINNT\system32\MyPlugin

var dllWin32Folder = getFolder("file:///", winDirectory+"\\MyPlugin\\");
//Install DLL to C:\Windows Folder
	copyErr = addFile("", VERSION, PLUGIN_FILE, dllWin32Folder, null);	
    if (copyErr != 0)
    {
    	logComment("First Install:"+copyErr);
    	return copyErr;
    }

// Install the XPT file to C:\WINNT\system32\MyPlugin folder

var xptWin32Folder = getFolder("file:///", winDirectory+"\\MyPlugin\\");
	copyErr = addFile("", VERSION, COMPONENT_FILE, xptWin32Folder, null);		
    if (copyErr != 0)
    {
    	logComment("First Install:"+copyErr);
    	return copyErr;
    }

Once the secondary installation has taken place, the Win32 Registry keys have to be updated to indicate information about where the secondary install location is, so that browsers can discover it. This is accomplished with the WinReg object that is exposed to XPInstall. The pieces all come together in the template below.

An XPInstall Template

We have provided you with a template for an install script which you might want to open in another tab or window. This install script does all of the following:

  • It installs both a DLL and an XPT file to the browser's plugins directory. The plugin itself is an imaginary one: MyPlugin. The variables that determine the plugin name, however, can be easily modified. This install.js file assumes that the plugin software that is to be installed consists of both a DLL and an XPT file, which is not always true. Many plugins may involve more than one DLL, or perhaps additional native code. It is, however, a safe assumption for most plugins, especially Macromedia's Flash Plugin which consists of a single DLL (on Windows this is npswf32.dll) and a single XPT file for scriptability (called flashplayer.xpt).
  • It further installs to a secondary location on the user's desktop. In particular, like many OCX files (ActiveX controls) it installs to a special directory within C:\WINNT\System32\, called C:\WINNT\System32\MyPlugin. XPInstall is able to determine what directory this is by the getFolder API call. We have written our own JavaScript function to contain all the secondary installation code -- function createSecondaryInstall()
  • And finally, it writes the required registry keys to Windows. This is done via the created function, called function registerPLID().

Certainly, this script is Windows-centric, but it is easy to port it to any other platform. Easier, perhaps, since the lengthy Win32 Registry manipulation need not occur on Linux or Mac OSX. The getFolder API provides you with enough "syntactic sugar" to determine other locations on the user's computer on different platforms and OS's. A single install.js is often capable of running on many different platforms.

Some Installation Concerns

This section gathers together some of the chief concerns about deploying XPI packages, notably: how ought a plugin download via XPI be initiated? And what about uninstalling plugins?

Triggering an XPInstall Download with a TriggerScript

A Trigger Script is web-page delivered piece of JavaScript that can automatically initiate an XPInstall download. This can be done conditionally, since Trigger Scripts can also detect what software has already been installed to the user's machine via XPInstall. This feature is useful for Web sites because:

  • HTML pages and JavaScript already have a way of detecting what plugins are installed. Additionally, via the InstallTrigger object which is exposed in Web pages, they can find out what the last version of the XPI Package was.
  • The InstallTrigger object can also start an XPI download automatically. This is useful because users can visit a Web site, and conditionally get served software (in a streamlined manner) that the Web site wants the user to have.

Trigger Scripts are a recommended way of initiating an XPInstall download.

Triggering an XPInstall Download from HTML

In a manner analogous to how SmartUpdate downloads were initiated by the pluginurl attribute of the embed tag, XPInstall downloads can also be initiated by HTML tags invoking plugins, notably via the codebase attribute of the object tag. This is analogous to how Internet Explorer downloads CAB files pointed to by the codebase attribute of the object tag. Here's an example of a hypothetical object tag used to invoke MyPlugin (an imaginary application):

	<object id="thePlugin" type="application/x-myplugin" width="100"
	height="100" codebase="http://location/XPI/myplugin.xpi">

<param .... >

In the above case, the codebase attribute points directly to the XPI Package, and if the browser can not identify any plugin to handle the (imaginary) application/x-myplugin MIME type, it will download the XPI Package.

Note: XPI Packages (files with the xpi extension) use the application/x-xpinstall MIME type. When serving XPI Packages from servers to clients, make sure that XPI Packages are served with this MIME type in the HTTP headers. Associate the application/x-xpinstall MIME type with XPI Packages.

The Uninstall Problem

In its current iteration, XPInstall does not have an affiliated uninstall technology. It can therefore only be used to install files or deliver native code installers to the client, and if uninstall is a legitimate concern, it might be wise to write a native code (EXE) uninstaller to remove the software. XPInstall can therefore be the "agent of delivery" to streamline the download of the EXE software, but ultimately, the logic of installation and uninstallation will be handled by EXE, which can then create files and registry entries and also clean up after itself upon removal.

Original Document Information

Triggering an XPInstall Download from HTML

In a manner analogous to how SmartUpdate downloads were initiated by the pluginurl attribute of the embed tag, XPInstall downloads can also be initiated by HTML tags invoking plugins, notably via the codebase attribute of the object tag. This is analogous to how Internet Explorer downloads CAB files pointed to by the codebase attribute of the object tag. Here's an example of a hypothetical object tag used to invoke MyPlugin (an imaginary application):

	<object id="thePlugin" type="application/x-xpinstall" width="100"
	height="100" codebase="http://location/XPI/myplugin.xpi">

<param .... >

In the above case, the codebase attribute points directly to the XPI Package, and if the browser can not identify any plugin to handle the (imaginary) application/x-myplugin MIME type, it will download the XPI Package.

Note: XPI Packages (files with the xpi extension) use the application/x-xpinstall MIME type. When serving XPI Packages from servers to clients, make sure that XPI Packages are served with this MIME type in the HTTP headers. Associate the application/x-xpinstall MIME type with XPI Packages.