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.
See also this article from XulPlanet's Main Tutorial.
There is a different sample install.js template located at http://downloads.mozdev.org/xsidebar/mods/. This version has been developed as part of the effort to port Firefox extensions to SeaMonkey from the xSidebar Project.
Pros: This version consolidates all the changable information at the top of the file. And it also knows how to install packaged components, search engines and default preferences.
Cons: Code is bloated since it has to cater for several different ways an extension author can package the .JAR file contained in the .XPI file.
XPI file structure
You can use the code below (taken from Pike's extensions ). It assumes the following structure of your XPI file:
sampleext.xpi chrome\ sampleext.jar content\ sampleext\ locale\ (optional) en-US\ sampleext\ ... skin\ (optional) classic\ sampleext\ ... install.js install.rdf (optional -- see above)
Code
// install.js // XpiInstaller // By Pike (Heavily inspired by code from Henrik Gemal and Stephen Clavering) var XpiInstaller = { // --- Editable items begin --- extFullName: 'Sample Extension', // The name displayed to the user (don't include the version) extShortName: 'sampleext', // The leafname of the JAR file (without the .jar part) extVersion: '1.0', extAuthor: 'Insert-your-name-here', extLocaleNames: null, // e.g. ['en-US', 'en-GB'] extSkinNames: null, // e.g. ['classic', 'modern'] extPostInstallMessage: null, // Set to null for no post-install message // --- Editable items end --- profileInstall: true, silentInstall: false, install: function() { var jarName = this.extShortName + '.jar'; var profileDir = Install.getFolder('Profile', 'chrome'); // Parse HTTP arguments this.parseArguments(); // Check if extension is already installed in profile if (File.exists(Install.getFolder(profileDir, jarName))) { if (!this.silentInstall) { Install.alert('Updating existing Profile install of ' + this.extFullName + ' to version ' + this.extVersion + '.'); } this.profileInstall = true; } else if (!this.silentInstall) { // Ask user for install location, profile or browser dir? this.profileInstall = Install.confirm('Install ' + this.extFullName + ' ' + this.extVersion + ' to your Profile directory (OK) or your Browser directory (Cancel)?'); } // Init install var dispName = this.extFullName + ' ' + this.extVersion; var regName = '/' + this.extAuthor + '/' + this.extShortName; Install.initInstall(dispName, regName, this.extVersion); // Find directory to install into var installPath; if (this.profileInstall) installPath = profileDir; else installPath = Install.getFolder('chrome'); // Add JAR file Install.addFile(null, 'chrome/' + jarName, installPath, null); // Register chrome var jarPath = Install.getFolder(installPath, jarName); var installType = this.profileInstall ? Install.PROFILE_CHROME : Install.DELAYED_CHROME; // Register content Install.registerChrome(Install.CONTENT | installType, jarPath, 'content/' + this.extShortName + '/'); // Register locales for (var locale in this.extLocaleNames) { var regPath = 'locale/' + this.extLocaleNames[locale] + '/' + this.extShortName + '/'; Install.registerChrome(Install.LOCALE | installType, jarPath, regPath); } // Register skins for (var skin in this.extSkinNames) { var regPath = 'skin/' + this.extSkinNames[skin] + '/' + this.extShortName + '/'; Install.registerChrome(Install.SKIN | installType, jarPath, regPath); } // Perform install var err = Install.performInstall(); if (err == Install.SUCCESS || err == Install.REBOOT_NEEDED) { if (!this.silentInstall && this.extPostInstallMessage) { Install.alert(this.extPostInstallMessage); } } else { this.handleError(err); return; } }, parseArguments: function() { // Can't use string handling in install, so use if statement instead var args = Install.arguments; if (args == 'p=0') { this.profileInstall = false; this.silentInstall = true; } else if (args == 'p=1') { this.profileInstall = true; this.silentInstall = true; } }, handleError: function(err) { if (!this.silentInstall) { Install.alert('Error: Could not install ' + this.extFullName + ' ' + this.extVersion + ' (Error code: ' + err + ')'); } Install.cancelInstall(err); } }; XpiInstaller.install();