aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/archive/mozilla/xpinstall/scripting_by_example/index.html
blob: fb43c1237c4499dcc44700478750916c58355e34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
---
title: Learn XPI Installer Scripting by Example
slug: Archive/Mozilla/XPInstall/Scripting_by_example
tags:
  - XPInstall
  - XPInstall_API_reference
translation_of: Archive/Mozilla/XPInstall/Scripting_by_example
---
<p></p><div class="warning"><p>Parts of this page show the use of the <a href="https://developer.mozilla.org/zh-CN/docs/XPInstall_API_Reference">XPInstall API</a>. The majority of this API is now deprecated and as of Gecko 1.9 no longer available. <a href="https://developer.mozilla.org/zh-CN/docs/Extensions">Extension</a>, <a href="https://developer.mozilla.org/zh-CN/docs/Themes">Theme</a>, and <a href="https://developer.mozilla.org/zh-CN/docs/Plugins">plug-in</a> developers must switch away from <code>install.js</code> based packages to the new <a href="https://developer.mozilla.org/zh-CN/docs/Bundles">packaging scheme</a> with an <code><a href="https://developer.mozilla.org/zh-CN/docs/Install_Manifests">install.rdf</a></code> manifest. In particular plugin developers should see <a class="new" href="https://developer.mozilla.org/zh-CN/docs/Shipping_a_plugin_as_a_Toolkit_bundle" rel="nofollow">how to package a plugin as an extension</a>.</p></div><p></p>

<p>This article uses the installer script from browser.xpi install package as the basis for discussing XPI installations in general. This <code><a href="cn/Learn_XPI_Installer_Scripting_by_Example/Installer_Script">installer script</a></code> is relatively short, but it exercises most of the important features of the XPInstall API, and it can easily be used as a template for other more general software installations. In this article, we use the unix install file, but the installers for all the platforms are quite similar, and you can easily take what you learn here and apply it to installations on any platform that mozilla supports.</p>

<h2 id="About_browser.xpi" name="About_browser.xpi">About <code>browser.xpi</code></h2>

<p><code>browser.xpi</code> is the XPI archive in which the main components of the Mozilla browser are archived for installation. Mozilla cross-platform installations use the XPI format as a way 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. That <code><a href="cn/Learn_XPI_Installer_Scripting_by_Example/Installer_Script">installer script</a></code> , usually named <code>install.js</code>, is the subject of this article.</p>

<p>First, a quick scan of the contents of the XPI file (which you can open using with any unzip utility) reveals the following high-level directory structure:</p>

<pre>install.js
bin\
  chrome\
  components
  defaults\
  icons\
  plugins\
  res\
</pre>

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

<p><img alt="mozilla directory on linux"></p>

<p>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.</p>

<h2 id="Overview_of_the_Install_Script" name="Overview_of_the_Install_Script">Overview of the Install Script</h2>

<p>XPI install scripts are written in JavaScript using XPInstall Engine syntax defined in the <a href="cn/XPInstall_API_Reference">XPInstall API Reference</a>.</p>

<p>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):</p>

<pre>initInstall();
if (verify_space()) {
   err = add_dirs_and_files;
   register_files;

   if (err==SUCCESS) { performInstall() };
   else { cancelInstall() };
}
</pre>

<p>As you can see in the <a href="cn/Learn_XPI_Installer_Scripting_by_Example/Installer_Script">code listing</a>, 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 must<em>initialize, add the files to be installed, and execute.</em></p>

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

<h3 id="Initializing_the_Installation" name="Initializing_the_Installation">Initializing the Installation</h3>

<p>All installations must begin with <code>initInstall()</code>. The <code>initInstall()</code> 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: <code> var err = initInstall("Netscape Seamonkey", "Browser", "6.0.0.2000110807"); </code></p>

<p>If you call a method on the <code>Install</code> object before <code>initInstall()</code>, you will get an error.</p>

<p>The <code>initInstall</code> 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 "6.0.0.2000110807." See <code><a href="cn/XPInstall_API_Reference/Install_Object/Methods/initInstall">initInstall</a></code> in the <a href="cn/XPInstall_API_Reference">XPInstall API Reference</a> for more information on the initialization process.</p>

<h3 id="Verifying_the_Target" name="Verifying_the_Target">Verifying the Target</h3>

<p>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 <code>verifyDiskSpace</code> function is called as a condition of the main installation block that starts at line 24).</p>

<pre> // this function verifies disk space in kilobytes
 function verifyDiskSpace(dirPath, spaceRequired)
 {
   var spaceAvailable;
   // Get the available disk space on the given path
   spaceAvailable = fileGetDiskSpaceAvailable(dirPath);

   // Convert the available disk space into kilobytes
   spaceAvailable = parseInt(spaceAvailable / 1024);
   // do the verification
   if(spaceAvailable &lt; spaceRequired)
   {
      logComment("Insufficient disk space: " + dirPath);
      logComment("  required : " + spaceRequired + " K");
      logComment("  available: " + spaceAvailable + " K");
      return(false);
   }
   return(true);
 }
</pre>

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

<pre>var communicatorFolder = getFolder("Program");
spaceAvailable = fileGetDiskSpaceAvailable(dirPath);
</pre>

<p><code>spaceRequired</code>, the other expected input to the <code>verifyDiskSpace</code> 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.</p>

<h3 id="Adding_Files_and_Directories_.28Full_of_Files.29_to_the_Install" name="Adding_Files_and_Directories_.28Full_of_Files.29_to_the_Install">Adding Files and Directories (Full of Files) to the Install</h3>

<p>Once you have verified that the target can accomodate the software to be installed and initialized the actual installation, you must add files and directories to the installation in order to have them installed. In the <code>browser.xpi</code> install script, the files are added in lines 26-41:</p>

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

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

  // create the plugins folder next to mozilla
  var pluginsFolder = getFolder("Plugins");
  if (!fileExists(pluginsFolder))
  {
      var ignoreErr = dirCreate(pluginsFolder);
      logComment("dirCreate() returned: " + ignoreErr);
  }
  else
      logComment("Plugins folder already exists");
</pre>

<p>In this case, the files are contained within a single directory, so calling the <code>Install</code> object's <code>addDirectory</code> method is sufficient to queue all the files in the archive for installation. The <code>addDirectory</code>, like <code>addFile</code>, handles both the source file location and the target location. In the example above, all of the contents of the "bin" directory in the archive are queued for installation, and the target of that installation (when the installation is actually begun with a call to <code>performInstall</code> at the end), is the <code>communicatorFolder</code> directory defined at line 22 as "Program."</p>

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

<h3 id="Registering_the_Software" name="Registering_the_Software">Registering the Software</h3>

<p>Registering software is sometimes a requirement of both the operating system and of the Netscape 6 platform. When you install new chrome, for example, like the <code>browser.xpi</code> install does, you need to alert the chrome registry to these changes, so that skins, user preferences, packaging lists, and localization bundles will all track the new software.</p>

<p>For registering software with the win32 operating system, the XPInstall API provides two special Install objects, <code>WinProfile</code> and <code>WinReg</code>. These two objects provide programmatic access to the Windows user profile and the Windows registry, respectively. The <code>browser.xpi</code> install script does not demonstrate the use of these objects, but see the XPInstall API Reference for more information about registering software with the win32 operating systems and other operating systems.</p>

<p>To register new Netscape 6-based software (e.g., plug-ins, new components, new themes, new packages) with the chrome registry, you must use the registerChrome function of the Install object. If successful, this function returns a "0" and makes entries into the<em>installed-chrome.txt</em> file in the <code>chrome</code> subdirectory, which is then used to regenerate the various RDF files that make up the chrome registry.</p>

<pre> 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/");
 ...
</pre>

<p>In lines 42-58, <code>registerChrome</code> 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 <code>registerChrome</code> function (it can also be used to support the now-deprecated<em>manifest.rdf</em> style of installation archive), the three parameters represent, in order, the chrome <code>SWITCH</code> 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.</p>

<p>See <code><a href="cn/XPInstall_API_Reference/Install_Object/Methods/registerChrome">registerChrome</a></code> in the XPInstall API Reference for more information about registering new packages with the chrome registry.</p>

<h3 id="Executing_the_Installation" name="Executing_the_Installation">Executing the Installation</h3>

<p>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:</p>

<pre>initInstall();
if (verify_space()) {
   err = add_dirs_and_files;
   register_files;

   if (err==SUCCESS) { performInstall() };
   else { cancelInstall() };
}
</pre>

<p>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.</p>

<p>The actual install code used to execute the installation appears in the<em>install.js</em> file as follows:</p>

<pre>if (err==SUCCESS)
  {
     err = performInstall();
        logComment("performInstall() returned: " + err);
  }

  else
  {
     cancelInstall(err);
	 logComment("cancelInstall() due to error: " + err);
  }
}
else
   cancelInstall(INSUFFICIENT_DISK_SPACE);
</pre>

<p><code>performInstall</code> 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.</p>

<p>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 <code>logComment</code>, described in the following section.</p>

<h2 id="Installation_Logging" name="Installation_Logging">Installation Logging</h2>

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

<p>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.</p>

<h2 id="Extending_the_Example" name="Extending_the_Example">Extending the Example</h2>

<p>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).</p>

<p>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.</p>

<p>Minimally, the installation script must:</p>

<ul>
 <li>Call <code>initInstall</code> 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)</li>
 <li>Find somewhere to put the installed files. In the example below, <code>getFolder</code> 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\".</li>
 <li>Add files to the initialized installation using <code>addFile</code>.</li>
 <li>Call performInstall to execute the installation.</li>
</ul>

<p>Here is an example of small but complete installation script.</p>

<pre>var xpiSrc = "cd_ripper.exe";
var xpiDoc = "README_cdrip";

initInstall("My CD Ripper", "cdrip", "1.0.1.7");
f = getFolder("Program");
setPackageFolder(f);
addFile(xpiSrc);
addFile(xpiDoc);

if (0 == getLastError())
	performInstall();
else
	cancelInstall();
</pre>

<p>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:</p>

<pre>function putIt()
{
  xpi={'CD_Ripper':'cdrip.xpi'};
  InstallTrigger.install(xpi);
}
...

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

<p>See the <a href="cn/XPInstall_API_Reference/InstallTrigger_Object">InstallTrigger</a> object in the XPInstall API Reference for more information on triggering installations.</p>

<div class="originaldocinfo">
<h2 id="Original_Document_Information" name="Original_Document_Information">Original Document Information</h2>

<ul>
 <li>Author(s): <a class="link-mailto" href="mailto:mailto:oeschger@netscape.com">Ian Oeschger</a></li>
 <li>Last Updated Date: 01/26/2006</li>
 <li>Copyright Information: Copyright (C) <a class="link-mailto" href="mailto:mailto:oeschger@netscape.com">Ian Oeschger</a></li>
</ul>
</div>

<p></p>