XPI 安裝腳本範例教學

本文以 browser.xpi 安裝套件為基礎,討論一般的 XPI 安裝程序。安裝腳本 installer script 雖短,但含括了 XPInstall API 大部分的重要功能,且可做為其他一般用途套件的安裝腳本樣本。本文在 unix 下安裝,不過各平台的安裝方式大同小異,你可以此變化安裝在各種 Mozilla 支援的平台。

關於 browser.xpi

browser.xpi 是 Mozilla 瀏覽器安裝主要元件的 XPI 封存檔。Mozilla 跨平台安裝以 XPI 格式作為組織、壓縮、以及軟體自動化安裝及更新的用途。XPI 的格式同 ZIP 及 JAR,為 PKZIP 壓縮後的檔案,只是內含可供管理安裝方式的腳本。本文目標即為此安裝腳本installer script(通常稱為 install.js)的教學。

任何能解 ZIP 壓縮檔的工具都能開啟 XPI 檔,先來看看裡面有什麼東西:


Note that this high-level structure parallels the directory structure of the installed browser very closely:

mozilla directory on linux

As you will see in the installation script, the contents of the archive are installed onto the file system in much the same way that they are stored in the archive itself, though it's possible to rearrange things arbitrarily upon installation--to create new directories, to install files in system folders and other areas.


XPI install scripts are written in JavaScript using XPInstall Engine syntax defined in the XPInstall API Reference.

Most installation scripts, including the one discussed here, take the following basic form (in pseudo-code and with links to the sections in which these installation steps are documented):


if (verify_space()) {
   err = add_dirs_and_files;

   if (err==SUCCESS) { performInstall() };
   else { cancelInstall() };

As you can see in the code listing, the verification process at the top is on lines 1 to 18; the file addition process, here part of the main installation block, is on lines 24 to 41; the registration part of the main installation block is on lines 42-58; and the execution at the end of the main block is on lines 59 to 71. If you choose not to register the installed software or do the verifications at the front end of the installation, then at a minimum, the install scripts mustinitialize, add the files to be installed, and execute.

Note also that when you call methods on the Install--as you do so often in installation scripts (getFolder, initInstall, addFile, and performInstall are all examples of common Install object methods)--the Install object is implicit; like the window object in regular web page scripts, the Install object does not need to be prefixed to the method.


All installations must begin with initInstall(). The initInstall() method on the Install object creates a new installation for the specified software and version. In the browser.xpi installation, this function appears at line 20: var err = initInstall("Netscape Seamonkey", "Browser", "");

如果你在 initInstall() 之前呼叫 Install 物件中的方法,會導致錯誤。

The initInstall method takes the following parameters: the display name of the package, the name of the package as it appears in the client registry, and the version, which can be expressed as a number or as an InstallVersion object. In the example above, "Netscape Seamonkey" is the display name, "Browser" is the registry name, and the version is "" See initInstall in the XPInstall API Reference for more information on the initialization process.


The first thing the installation script does when it's executed is to check that there is adequate disk space for the software to be installed, where the verifyDiskSpace function is called as a condition of the main installation block that starts at line 24).

 // 先檢查磁碟剩餘空間
 function verifyDiskSpace(dirPath, spaceRequired)
   var spaceAvailable;
   // 取得安裝磁碟之剩餘空間
   spaceAvailable = fileGetDiskSpaceAvailable(dirPath);

   // 將剩餘空間單位化為 KB
   spaceAvailable = parseInt(spaceAvailable / 1024);
   // 開始檢查
   if(spaceAvailable < spaceRequired)
      logComment("Insufficient disk space: " + dirPath);
      logComment("  required : " + spaceRequired + " K");
      logComment("  available: " + spaceAvailable + " K");

In the verifyDiskSpace block, fileGetDiskSpaceAvailable is called with dirPath as its expected input. This input is defined in line 22, where getFolder() is used to assign a value to the communicatorFolder variable representing the "Program" folder on the local system:

var communicatorFolder = getFolder("Program");
spaceAvailable = fileGetDiskSpaceAvailable(dirPath);

spaceRequired, the other expected input to the verifyDiskSpace function, is given as 17311 kilobytes on line 19. Inside the function, the two sizes are compared and if the available space is larger than the required space, the installation proceeds.

為 Install 物件加入檔案及內含檔案的目錄

一旦確保程式可以開始安裝,就該把想放的檔案加入安裝程序。在 browser.xpi 中,此程式段位於 26 到 41 行:

  err = addDirectory("Program",
                     "bin",              // jar source folder
                     communicatorFolder, // target folder
                     "",                 // target subdir 
                     true );             // force flag 

  logComment("addDirectory() returned: " + err);

  // 建立 plugins 目錄
  var pluginsFolder = getFolder("Plugins");
  if (!fileExists(pluginsFolder))
      var ignoreErr = dirCreate(pluginsFolder);
      logComment("dirCreate() returned: " + ignoreErr);
      logComment("Plugins folder already exists");

本例檔案都放在單一目錄中, 所以採用 Install 物件的 addDirectory 方法將壓縮檔目錄中的檔案一併加入。addDirectoryaddFile 兩種方法都要指定來源與目的路徑,在此例中是把「bin」目錄中的檔案列為來源,並要求於程式正式呼叫 performInstall 時將檔案安裝到 communicatorFolder 目錄(此變數於第 22 行指定為「Program」)。

"Program" is one of a short list of keywords that can be used in place of full path names in methods such as addFile. "Program" represents the directory where software itself is installed (e.g., C:\Program Files\ on win32 systems), as opposed to supporting directories like "Components", "Chrome", or "Temporary" (see getFolder in the XPInstall API Reference for a list of keywords).


對於一個軟體來說,有時候需要同時在作業系統和 Netscape 6 平台上進行登記「登錄碼」。當你安裝了一個新的 chrome 像是 browser.xpi 時,你需要讓 chrome 登錄碼把這些更新登記在起來;如此一來,面板(skin)、使用者介面(user preference)、檔案清單(packaging list)、本地化文件(localization bundle)就會自動與新的軟體對應。

對於在 win32 作業系統上登記軟體,XPInstall API 提供兩個特別的物件-WinProfileWinReg。它們能夠對 Windows 使用者資料和 Windows 登錄碼進行對應的操作。browser.xpi 安裝腳本並不強制你使用這些物件。關於在 win32 平台上和其他作業系統登記軟體,詳情可以參考 XPInstall API Reference。

而要利用 chrome 登錄碼登記基於 Netscape 6 的新軟體,像是一些外掛(plug-in)、元件(component)、佈景主題(theme)和套件(package),你需要使用 Install 物件中的 registerChrome 函數。如果執行成功,這個函數會回傳一個「0」並且將這筆紀錄寫進 chrome 的子目錄「installed-chrome.txt」這個檔案當中以便以後其他的 chrome 能夠同步更新千變萬化的 RDF 檔案。

 var cf = getFolder("Chrome");
 registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"toolkit.xpi"),"content/global/");
 registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"browser.xpi"),"content/communicator/");
 registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"browser.xpi"),"content/editor/");
 registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"browser.xpi"),"content/navigator/");
 registerChrome(SKIN | DELAYED_CHROME, getFolder(cf,"modern.jar"),"skin/modern/communicator/");
 registerChrome(SKIN | DELAYED_CHROME, getFolder(cf,"modern.jar"),"skin/modern/editor/");

在第 42 行至 58 行,只要有不同的資料夾中存在需要紀錄在 chrome 紀錄碼中的內容, registerChrome 就會被呼叫。 In lines 42-58, registerChrome is called as many times as there are different directories that contain content that needs to be registered with the chrome registry. Note that in the first few lines of this process, new content from the XPI is being registered, and in the remainder, it is new skin information. In this most common form of the registerChrome function (it can also be used to support the now-deprecatedmanifest.rdf style of installation archive), the three parameters represent, in order, the chrome SWITCH used to indicate what kind of software is being registered, the target destination of the software (e.g., the "Chrome" folder in the example above), and the path within the XPI (or JAR theme archive) where the contents.rdf file is located.

See registerChrome in the XPInstall API Reference for more information about registering new packages with the chrome registry.


Once you have added all the files to the installation, the final step is to actually execute the installation. Note that until this point, the install calls you have been making on the Install object are preliminary only. Recall that an install process takes the following general form:

if (verify_space()) {
   err = add_dirs_and_files;

   if (err==SUCCESS) { performInstall() };
   else { cancelInstall() };

In this arrangement, the actual execution of the installation is checked against the errors returned from the addition of files to the installation, which may itself have been conditioned on some verification of version and necessary disk space.

The actual install code used to execute the installation appears in theinstall.js file as follows:

if (err==SUCCESS)
     err = performInstall(); 
        logComment("performInstall() returned: " + err);

	 logComment("cancelInstall() due to error: " + err);

performInstall is the function used to execute the install once it has been initialized and loaded, and it is the last step to installing the software. Note that in the example above, the installation is cancelled if the error code from the file addition process returns success (0), and also cancelled outside the main block if the earlier verification process is not successful.

Note also the comments that indicate the success of various steps in the process--including the performInstall and cancelInstall steps--are written to the install log using the logComment, described in the following section.


Logging is an important feature of the XPInstall API that can help you streamline and debug your installations. In the example in the Executing the Installation section and in many places in the installation script, the logComment API is used to write data to a log file that can then be reviewed when things don't go as planned.

The install log is created in the product directory by default (where the browser executable is). If the installation doesn't have proper permission, the install log is written to the user's profile directory. Respectively, these directories correspond to the "Program" and "Current User" keywords for the getFolder method.


What does all this mean to you? How can this information be adapted for your own installations? In this final section, we describe the application of the XPInstall technology described here in the creation and deployment of a very simple installation script and installation archive (XPI).

Say you have a simple executable and a README file that goes with it, and you want to make it available for installation from a XPI. After putting these two files in a XPI (which, as described above, is simply a ZIP file with an install.js script at the top and a suffix of '.xpi'), the next step is to add an installation script to the XPI.

Minimally, the installation script must:

  • Call initInstall with the name and version of the executable (the version is not optional, though you may or may not use the version in subsequent installations or updates)
  • Find somewhere to put the installed files. In the example below, getFolder is used with the "Program" keyword to specify the browser's program directory as the target for installation. Since I am using NS6 right now on a Windows machine, that target directory is "C:\Program Files\Netscape\Netscape 6\".
  • Add files to the initialized installation using addFile.
  • Call performInstall to execute the installation.

Here is an example of small but complete installation script.

var xpiSrc = "cd_ripper.exe";
var xpiDoc = "README_cdrip";

initInstall("My CD Ripper", "cdrip", "");
f = getFolder("Program");

if (0 == getLastError())

The example above shows this minimal installation. This install script does not include any version or disk space checking, very little error checking, only a single executable, no registration, and no commenting. It does, however, take the executable and the README file and install them on the user's system. Note also that for the installation script in a XPI to be automatically triggered from a web page, you must use a "trigger script." The following InstallTrigger function, called from an event handler on a regular web page, will point to the remotely-hosted XPI (called here 'cdrip.xpi') and trigger its installation:

function putIt() 

<a href="#" onclick="putIt();">install the CD Ripper Now!</a>

See the InstallTrigger object in the XPInstall API Reference for more information on triggering installations.