Once your application is packaged, the next step is to create a cross-platform installation, or XPI. A XPI is a special file archive that contains your Mozilla package(s) and its own installation instructions. The relationship of the various parts of the installation process -- the XPI itself, the internal installation script, the trigger script that begins the installation, and the Mozilla browser -- can be visualized in Figure 6-4.
Mozilla cross-platform installations use XPIs as the file format in which to organize, compress, and automate software installations and software updates. A XPI is a PKZIP-compressed archive (like ZIP and JAR files) with a special script at the highest level that manages the installation. A quick scan of the contents of a XPI file (which you can open using with any unzip utility) reveals the high-level directory structure shown in Example 6-8.
Note that the high-level structure in Example 6-8 parallels the installed browser's directory structure very closely. The bin directory at the highest level of the archive corresponds to the Mozilla application directory. On Unix, this directory is actually called bin, where all of the resources are stored. On other platforms, the installation puts these resources in the application directory itself.
In the case of the Mozilla browser, the XPIs manage the transfer and registry of all components -- the chrome files in the JARs, the executables, the default user information, and the libraries. As you will see in the installation script, the contents of the archive are installed onto the filesystem in much the same way as they are stored in the archive itself, although it's possible to rearrange things arbitrarily upon installation -- to create new directories, install files in system folders and other areas, or execute software that handles other aspects of the installation, such as third-party installers.
When the items to be installed are very simple, XPIs may contain nothing more than a single executable and the install script itself, as shown in Figure 6-5. In this figure, the WinZip utility has been used to display the contents of a XPI that installs a text editor on a Win32 system.
This example uses XPInstall technology to install something that may or may not be a Mozilla application. The install.js script in Example 6-8 would look like this. In Mozilla application development, however, XPIs often contain JAR files that are installed as new packages in the Mozilla distribution. To make a XPI for your package, use any zip software (applications or extensions that will be part of the main Mozilla distribution are required to use the free zip utility from InfoTools so that they can be run as part of the build process) to archive your files.
Technically, only the internal installation script distinguishes JARs and XPIs. However, Mozilla treats them differently. Since JARs do not include this installation script, they cannot install full content or applications by themselves. In this case, "content" means XUL, XBL, or JavaScript files that have script access to XPCOM. Files of this kind that are in JARs are denied access to XPConnect and are not registered as content in the chrome registry. JARs are used primarily to install locales, or language packs, and skins.
Skins that contain scripts and bindings (see the section Section 4.5.3 and the Evil Skins sidebar, both in Chapter 4) are seen more as chrome content and must be installed in XPIs if they are to be fully functional. Like executables that are fetched from the Web, XPIs can cause trouble when downloaded by unprepared users since the software in XPIs are given the same privileges on the Mozilla platform that the browser chrome itself has.
The characteristics and usage of an XPI are:
Has an install.js file
Can install anything via XPInstall API
PKZip-compressed
May contain one or more JAR packages
Mozilla installation
Used for new packages
The characteristics and usage of a JAR are:
Contains only the resources themselves
Installed with an external script
May be installed inside a XPI
PKZip-compressed
Themes
Languages packs
Storage archive for installed components
Mozilla uses the presence of this internal installation script and not the file suffix (which can be changed easily enough) to determine what type of archive it is. Accordingly, JARs are most often used to install new themes and new language packs, which can be done by using just a brief trigger script on a web page loaded into Mozilla. When they contain new chrome -- new XUL and JavaScript that will access the Mozilla objects via XPConnect -- JAR files must be put within a XPI that can register them properly.
Most new packages in Mozilla are installed by means of installation scripts. These scripts are written in JavaScript. Unlike regular web page JavaScript, however, which uses window as the top-level object, installation scripts have a special install object context. As you will see in the following examples, the Install object -- even when it's implicit and not prefixed to the object methods -- is the top-level object upon which most methods are called.
At their very simplest, installation scripts look something like Example 6-9.
These methods are being called on the Install object, which is implicit in an installation script. Example 6-10 is an equivalent (and still very compact) installation script. The Install object is prefixed explicitly to the install functions.
As they become more complicated, install scripts may set up and arrange target directories in more specific ways, do more error checking, and include variables to make the code more readable and reusable, as seen in the longer install script in Example 6-11.
XPInstall technology makes software installation from a web page very easy. When a link on a web page kicks off the installation of new software, "trigger" code on the web page starts the process and gets the XPI onto the local system. Once this is done, the install.js file in the XPI can take up the full installation and registration of new files.
In Example 6-12, the trigger script -- placed in an onclick event handler on the page -- starts the installation of a new theme on the local machine, where the XPI can be unpacked and its installation script executed in full.
Later, we discuss in more detail the Install object, whose methods are typically called in installation scripts.
When you have a simple Mozilla package like a theme, which does not need special security privileges and which is always installed in a particular location, you can leave out the XPI and its internal installation script altogether and use a trigger script like Example 6-13 and a regular JAR file to download and register the new package.
The only difference here is that the item to be installed is a JAR and not a XPI file. Also, no internal installation script is present (since of the two, only XPIs carry their own install.js file). When the InstallTrigger object gets a JAR with a package manifest it can read and a package type that doesn't break the security boundary for applications (i.e., a new theme, a new language pack, or new content that doesn't use XPConnect), it can download and register that package with the chrome registry and make it available to users. The JAR and a trigger script like the one just shown are all you need in this case. See the earlier section, Section 6.3.1.2 for more detail on the limitations of scriptless installs.
Though the XPI format is by definition cross-platform, the files you distribute within it may need to be installed on a per-platform basis. The platform can be retrieved using the platform property of the Install object or the getFolder function. Example 6-14 shows a JavaScript function for install.js for returning the platform that the script is running on.
It's often necessary to check the platform when you install new language packs. At the time of this writing, issues related to write access to the chrome folder on Unix systems require some forking in the install script. There are also certain JAR files that are installed on a per-platform basis in language packs. Example 6-14 covers the three major platforms (Windows, Mac, and *nix). Here is how you use it:
platformNode = getPlatform( ); if (platformNode != 'unix') { // do Unix script and files } else if (platformNode != 'win') { // do Windows script and files } else { // mac // do Mac script and files }
When you are testing your XPI or need a way to troubleshoot installation problems, one of the best methods is to consult the installation log file. This file is called install.log and lives in the bin directory.
The install.log file is generated the first time you try to install software in Mozilla and appended to for each subsequent installation. The format of the file -- in which the URL and date of the installation appear as a heading -- makes it easy to find the installation you are checking on in the install log.
Example 6-15 shows the output in install.log after a single successful installation.
In your install.js file, you can use the method logComment to create output other than these standard logging messages. This can be very useful for debugging your install scripts or providing extra feedback:
logComment( "Installation started ..." );
The output for this call will appear in install.log formatted like this:
** Installation started ...
When installation is not smooth, Mozilla outputs an error code to track down what is happening. For example, if you declare a constant variable twice in your install script, you will receive notification of an script error in the UI, and this error will be logged in install.log:
** Line: 4 redeclaration of const X_JAR_FILE Install **FAILED** with error -229 -- 07/01/2002 11:47:53
A full list of error codes can be found at http://lxr.mozilla.org/seamonkey/source/xpinstall/src/nsInstall.h or in the XPInstall API Reference at http://developer.netscape.com/docs/manuals/xpinstall/err.html.
Though XPInstall is enabled by default, there is preference to turn it on and off in the user profile preferences file (prefs.js). To disable XPInstall, set the preference like this: |
user_pref("xpinstall.enabled", false);
XPInstall is a technology used for cross-platform installation. Mozilla uses it extensively to install new packages, but as a general-purpose technology, it can be used to install anything on your computer. The XPI file format we described in the section Section 6.3.1 earlier in this chapter is the basic unit of exchange in an XPInstall and the installation script manages the installation.
Installation scripts -- whether they appear within the XPI, on a web page as an external "trigger script," or elsewhere in JavaScript -- use the XPInstall API to do all the heavy lifting. The XPInstall API includes installation functions (Example 6-16) organized into such high-level objects as the Install object, the InstallTrigger object, and the File object, which you can use to install new Mozilla packages.
In addition to the XPInstall API installation functions, installation scripts often call methods on the chrome registry itself. As described earlier in this chapter in the Section 6.2.4 section, the chrome registry handles the registration of new files and packages on the local system, the maintenance of user configurable data (such as what skin or theme you currently selected), and several utility functions used to make installations easier and more successful.
The Install object is the main object in the XPInstall API. It provides most of the methods and properties used in installation scripts.
initInstall(displayName, name, version, flags)
The initInstall( ) method that initializes the installation process takes the following parameters: displayName is the name you give to the installation itself; name is the name of the package to be installed (which must match the name given to the package in the manifests); version is the version of the package being installed (also specified in the manifest); and flags is an optional parameter reserved for future use (which is set to "0" by default and about which you don't have to worry).
Example: initInstall("Example Installation", "xfly", "0.9", 0); addFile(file)
The addFile( ) method adds a single file to the initialized installation. file is a pointer to the file in the XPI that will be installed.
Example: addFile("simple.exe"); err = performInstall( )
The performInstall( ) method starts the installation that you set up.
Example: performInstall( );
The Install object exposes the methods listed in Table 6-1.
Table 6-1. Install object methods
Method |
Description |
---|---|
AddDirectory |
Unpacks an entire subdirectory. |
AddFile |
Unpacks a single file. |
Alert |
Displays an Alert dialog box with a message and an OK button. |
CancelInstall |
Aborts the installation of the software. |
Confirm |
Displays a Confirm dialog box with the specified message and OK and Cancel buttons. |
deleteRegisteredFile |
Deletes the specified file and its entry in the Client Version Registry. |
Execute |
Extracts a file from the XPI file to a temporary location and schedules it for later execution. |
Gestalt |
Retrieves information about the operating environment (Mac OS only). |
GetComponentFolder |
Returns an object representing the directory in which a component is installed. |
GetFolder |
Returns an object representing a directory, for use with the addFile method. |
GetLastError |
Returns the most recent nonzero error code. |
getWinProfile |
Constructs an object for working with a Windows .ini file. |
getWinRegistry |
Constructs an object for working with the Windows registry. |
InitInstall |
Initializes installation for the given software and version. |
LoadResources |
Returns an object whose properties are localized strings loaded from the specified property file. |
LogComment |
Adds a comment line to the install log. |
Patch |
Applies a set of differences between two versions. |
PerformInstall |
Finalizes the installation of software. |
RegisterChrome |
Registers chrome with the chrome registry. |
ResetError |
Resets a saved error code to zero. |
setPackageFolder |
Sets the default package folder that is saved with the root node. |
When you have very simple installations -- such as when you want to install a new skin -- you may not need to use the services from the Install object. Besides providing the services necessary for "triggering" the downloading of a package from a web site, the InstallTrigger object offers some simple methods for installing when you do not need to rearrange of the disk, register complications, or do other install-type preparation (see Table 6-2).
Table 6-2. InstallTrigger interface showing the role of the InstallTrigger object in the overall installation process
Method |
Description |
---|---|
compareVersion |
Compares the version of a file or package with the version of an existing file or package. |
Enabled |
Indicates whether the Software Installation is enabled for this client machine. |
getVersionInfo |
Returns an InstallVersion object representing the version number from the Client Version Registry for the specified software or component. |
Install |
Installs one or more XPI files on the local machine. |
installChrome |
Installs new skin or locale packages in Netscape 6 and Mozilla. |
startSoftwareUpdate |
Initiates the download and installation of specified software. Note: deprecated in favor of install. |
This web page installation script defines its own install method in which a callback parameter on the InstallTrigger's own install( ) method checks the success of the installation and displays a relevant alert for the user (as shown in Example 6-17).
The XPInstall technology downloads and installs any software on any machine using Mozilla or Netscape 6/7. The same Install object methods that download, register, and install new Mozilla packages (e.g., new themes or new Mozilla applications like xFly) can be used to download other executables and software into any location on the local machine.
As with Mozilla application installs, you use an installation script within a XPI to initialize the installation, add the files you want to the installation, and then perform the install and put the software in the designated locations. Note that non-Mozilla software installations do not include a registration step, since the chrome registry does not track non-Mozilla software or any more general additions to the operating system. Example 6-18 shows a simple and typical non-Mozilla installation.
Refer to the "XPInstall API Reference" on http://developer.netscape.com for more detailed information about the XPInstall API and how it can be used in more complex installations.
You may have noticed an uninstall( ) method on the Install object in the XPInstall API. This method does some of the work you need to do to uninstall packages from Mozilla, but it's a buggy process and doesn't finish the job.[1] Beyond the physical removal of the package resources during the uninstall, several RDF files in the chrome registry need to be updated, and the XPInstall uninstall( ) does not get to some of these files.
Fortunately, the JSLib JavaScript developer's library has a well-implemented uninstall function, which you can use by importing the uninstall.js file and calling uninstall on the package you want uninstalled. uninstall.js is one of the JS file collections that comprise the JSLib.
Once you install JSLib, using the uninstall method is simple:
include("chrome://jslib/install/uninstall.js"); var p = new Uninstall('myPackageName'); p.removePkg( );
You might want to put this uninstall routine in a function so you can reuse it.
function unInstall(pkg) { var p = new Uninstall(pkg); p.removePkg( ); }
This method removes the resources themselves and deletes all references to the package in the chrome registry. The pkg parameter is the name of the package as defined in the manifest for that package. The xFly package manifest, for example, defines "xfly" as the name of the package, as shown in Example 6-19.
Example 6-9 comes from the content package manifest for xFly, which is similar to the full content manifest for the XMLTerm application you saw in Example 6-4.
To uninstall the xFly package, then -- as you should do to the working version you have as you develop before installing the final version -- hook up a menuitem to call the uninstall routine:
<menuitem id="uninstall-item" label="Uninstall xFly" oncommand="unInstall("xfly")" />
This menuitem should have access to a JavaScript file and contains the following code:
include("chrome://jslib/install/uninstall.js"); function unInstall(pkg) { var p = new Uninstall(pkg); p.removePkg( ); }
[1] | Currently, some open bugs in Bugzilla are tracking the progress of this method and its improvement. |