mozilla

版本 429251 / 自引导型扩展

  • 版本网址缩略名: Extensions/引导型扩展
  • 版本标题: 引导型扩展
  • 版本 id: 429251
  • 创建于:
  • 创建者: xcffl
  • 是否是当前版本?
  • 评论

修订内容

{{ gecko_minversion_header("2.0") }}

传统形式的扩展包含覆盖接口程序段(overlay),应用程序可以从扩展的程序包中载入 XUL,并自动将其覆盖在自己的 UI 之上。这使得创建的扩展加入到应用程序的用户界面比较容易,但同时更新、安装或禁用扩展需要应用程序重启。

Gecko 2.0 {{ geckoRelease("2.0") }} 引入了自引导型(bootstrapped)扩展。这是种特别的扩展,它们不使用覆盖界面来将它们的用户界面应用到应用程序中,而是用程序将它们自己插入到应用程序。这是通过包含在扩展中的一个特制的脚本文件来实现,脚本中包含了一些函数可供浏览器调用,来指挥扩展的安装、卸载、启动和关闭。

应用程序所需做的就是调用该脚本文件;由扩展负责添加和去除它的用户界面,和处理任何其它所需的设置和关闭任务。

本文论述了自引导型扩展将如何工作。

作为题外话,所有用 Add-on SDKAdd-on Builder 创建的扩展都是自引导型的;但是,所有的引导代码都是为您特别生成的,所以实际上您并不需要真的去研究它。

启动和关闭程序(process)

自引导型扩展的一个关键特征是,它们必须按照应用程序的要求启动和关闭。当扩展的 startup() 函数被调用,它必须手动将它的用户界面和其它行为注入到应用程序中。同样,当它的 shutdown() 函数被调用,它必须移除添加到应用程序中的任何东西,也包括到它的任何对象的所有引用。

startup() 函数会在多个场景中被调用;比如:

  • 第一次安装扩展,假设它兼容该应用程序且被启用。
  • 使用附加组件管理器启用该扩展。
  • 应用程序启动,如果扩展为启用并且兼容应用程序。

shutdown() 函数会被调用的一些场景:

  • 卸载该扩展,如果它为启用状态。
  • 禁用该扩展。
  • 用户退出应用程序,如果该扩展为启用。

修改应用程序用户界面的说明

引导型附加组件中的 chrome.manifest

您可以在引导型附加组件中使用 chrome.manifest 文件来:

  1. 通过 chrome:// URL(在清单(manifest)中使用 contentlocaleskin 指令)使您的附加组件的内容生效;
  2. 用您的内容替换已经存在的 chrome:// URI(使用 override 指令)。

不是所有的 chrome.manifest 指令都被引导型附加组件支持,比如在引导型附加组件中,您仍然不能注册 XUL 覆盖界面。详见 chrome.manifest 文档。

在 Firefox 10 及以上版本中,放在附加组件 XPI 根目录下的 chrome.manifest 文件(比如与 install.rdf 同级)会被自动加载。在 Firefox 8 和 9 中,您必须手动加载/卸载清单,使用 {{ ifmethod("nsIComponentManager", "addBootstrappedManifestLocation") }} 和 {{ ifmethod("nsIComponentManager", "removeBootstrappedManifestLocation") }}。该特征在 Firefox 8 以前的版本中无效。

手动添加用户界面

如果您决定继续尝试开发一个修改应用程序用户界面的引导型扩展,这儿有几个建议给您。

您需要在相关应用程序中调用 {{ domxref("document.getElementById()") }},通过 UI 元素的 ID 来查找它们,然后操纵它们来注入您的 UI。例如,您可以通过 document.getElementById("main-menubar") 来访问 Firefox 的菜单栏。

确保在关闭时移除您添加的任何用户界面。

创建引导型扩展

为标示一个扩展为可引导的,您需要添加下列元素到它的安装清单

<em:bootstrap>true</em:bootstrap>

然后您需要添加一个 bootstrap.js 文件,它包含所要求的函数;在扩展的包中,它应该与 install.rdf 文件同级。

向后兼容

因为旧版本的 Firefox 并不知道 bootstrap 属性或 bootstrap.js 文件,创建一个既能作为可引导扩展又能作为传统扩展来工作的 XPI 并不很困难。按照可引导扩展来创建您的扩展,然后同样地添加传统的覆盖界面。新版本的 Firefox 将使用 bootstrap.js 脚本并忽略部件(components)和覆盖界面,同时旧版本将使用覆盖界面。

引导切入点(entry points)

bootstrap.js 脚本应该包含几个特殊函数,浏览器调用它们来管理扩展。该脚本被放在一个有特权的(privileged)沙箱中执行,这个沙箱一直被保存(cached)到扩展关闭。

startup

当扩展需要启动它自己时被调用。它发生在应用程序启动时,或当启用被禁用的扩展时(或在它为了安装更新而被关闭后)。可见,在应用程序的生命期内,它会被多次调用。

您的附加组件应当在这时注入 UI,启动任何可能需要运行的任务,等等。

void startup(
  data,
  reason
); 
参数
data
引导数据结构
reason
原因常量之一,表明为什么扩展被启动。可以是 APP_STARTUPADDON_ENABLE、ADDON_INSTALLADDON_UPGRADEADDON_DOWNGRADE 之一。

shutdown

当扩展需要关闭它自己时被调用,比如当应用程序退出时,或当即将更新或禁用扩展时。在这里必须移除所有已被注入的用户界面,关闭所有任务,并处理掉所有对象。

void shutdown(
  data,
  reason
);
参数
data
引导数据结构
reason
原因常量之一,表明为什么扩展被关闭。可以是 APP_SHUTDOWNADDON_DISABLE、ADDON_UNINSTALL、ADDON_UPGRADEADDON_DOWNGRADE 之一。

install

您的引导脚本必须包括 install() 函数,应用程序在安装、升级或降级扩展后,第一次调用 startup() 之前调用它。

注意:如果从未启动扩展,则不会调用该方法;例如,如果扩展虽被安装但并不兼容当前版本的应用程序,且在变为兼容之前被卸载,则 install() 始终不会被调用。但是,如果扩展被升级到一个兼容应用程序的版本,将在第一次调用 startup() 之前调用它的 install() 函数。
void install(
  data,
  reason
); 
参数
data
引导数据结构
reason
原因常量之一,表明为什么扩展被安装。可以是 ADDON_INSTALLADDON_UPGRADEADDON_DOWNGRADE 之一。

uninstall

该函数在卸载扩展的某个版本之前,最后一次调用 shutdown() 之后被调用。如果始终未调用 install(),也不会调用此函数。

注意:记住这一点很重要——即使对于当前被禁用或不兼容当前应用程序的扩展,都会被调用 uninstall()。鉴于此,在实现该函数时,优雅地处理那些也许并不存在于应用程序中的 API 变得非常重要。如果一个第三方应用程序在 Firefox 未运行时移除了该扩展,该函数也不会被调用。
void uninstall(
  data,
  reason
); 
参数
data
引导数据结构
reason
原因常量之一,表明为什么扩展被卸载。可以是 ADDON_UNINSTALLADDON_UPGRADEADDON_DOWNGRADE 之一。

原因常量

上述引导函数都接受一个 reason 参数,该参数向扩展解释为什么调用该函数。 这些原因常量如下:

常量 描述
APP_STARTUP 1 应用程序启动。
APP_SHUTDOWN 2 应用程序关闭。
ADDON_ENABLE 3 启用附加组件。
ADDON_DISABLE 4 禁用附加组件。(同时被错用于卸载
ADDON_INSTALL 5 安装附加组件。
ADDON_UNINSTALL 6 卸载附加组件。
ADDON_UPGRADE 7 升级附加组件。
ADDON_DOWNGRADE 8 降级附加组件。

引导数据

每个切入点被传入一个简单的数据结构,它包含一些关于引导附加组件的有用信息。调用 AddonManager.getAddonByID() 可以获得更多关于附加组件的信息。该数据是一个简单的 JavaScript 对象,它包括以下属性:

属性 类型 描述
id string 被引导附加组件的 ID。
version string 被引导附加组件的版本。
installPath nsIFile 被引导附加组件的安装位置。可能是一个目录或一个 XPI 文件,这取决于安装该附加组件时是否解包。
resourceURI nsIURI 附加组件文件根目录的 URI,可能是 jar:file: URI,这取决于安装该附加组件时是否解包。{{ gecko_minversion_inline("7.0") }}
oldVersion string 以前的安装版本,如果原因是 ADDON_UPGRADEADDON_DOWNGRADE,并且方法是 installstartup。{{ gecko_minversion_inline("22.0") }}
newVersion string 将要安装的版本,如果原因是 ADDON_UPGRADEADDON_DOWNGRADE,并且方法是 shutdownuninstall。{{ gecko_minversion_inline("22.0") }}

注意:附加组件可能会在程序启动时升降级,此时 startup 方法的原因是 APP_STARTUP,并且不会设置 oldVersion 属性。 另外需注意,在某些情形下有可能发生附加组件升降级但 uninstall 方法没有被调用的情况。

延伸阅读

修订版来源

<p>{{ gecko_minversion_header("2.0") }}</p>
<p>传统形式的扩展包含<strong>覆盖接口程序段</strong>(overlay),应用程序可以从扩展的程序包中载入 XUL,并自动将其覆盖在自己的 UI 之上。这使得创建的扩展加入到应用程序的用户界面比较容易,但同时更新、安装或禁用扩展需要应用程序重启。</p>
<p>Gecko 2.0 {{ geckoRelease("2.0") }} 引入了<strong>自引导型(bootstrapped)扩展</strong>。这是种特别的扩展,它们不使用覆盖界面来将它们的用户界面应用到应用程序中,而是用程序将它们自己插入到应用程序。这是通过包含在扩展中的一个特制的脚本文件来实现,脚本中包含了一些函数可供浏览器调用,来指挥扩展的安装、卸载、启动和关闭。</p>
<p>应用程序所需做的就是调用该脚本文件;由扩展负责添加和去除它的用户界面,和处理任何其它所需的设置和关闭任务。</p>
<p>本文论述了自引导型扩展将如何工作。</p>
<p>作为题外话,所有用 <a class="link-https" href="https://addons.mozilla.org/en-US/developers/docs/sdk/latest/">Add-on SDK</a> 或 <a class="link-https" href="https://builder.addons.mozilla.org/">Add-on Builder</a> 创建的扩展都是自引导型的;但是,所有的引导代码都是为您特别生成的,所以实际上您并不需要真的去研究它。</p>
<h2 id=".E5.90.AF.E5.8A.A8.E5.92.8C.E5.85.B3.E9.97.AD.E7.A8.8B.E5.BA.8F.EF.BC.88process.EF.BC.89">启动和关闭程序(process)</h2>
<p>自引导型扩展的一个关键特征是,它们必须按照应用程序的要求启动和关闭。当扩展的 <code>startup()</code> 函数被调用,它必须手动将它的用户界面和其它行为注入到应用程序中。同样,当它的 <code>shutdown()</code> 函数被调用,它必须移除添加到应用程序中的任何东西,也包括到它的任何对象的所有引用。</p>
<p><code>startup()</code> 函数会在多个场景中被调用;比如:</p>
<ul>
  <li>第一次安装扩展,假设它兼容该应用程序且被启用。</li>
  <li>使用附加组件管理器启用该扩展。</li>
  <li>应用程序启动,如果扩展为启用并且兼容应用程序。</li>
</ul>
<p><code>shutdown()</code> 函数会被调用的一些场景:</p>
<ul>
  <li>卸载该扩展,如果它为启用状态。</li>
  <li>禁用该扩展。</li>
  <li>用户退出应用程序,如果该扩展为启用。</li>
</ul>
<h2 id=".E4.BF.AE.E6.94.B9.E5.BA.94.E7.94.A8.E7.A8.8B.E5.BA.8F.E7.94.A8.E6.88.B7.E7.95.8C.E9.9D.A2.E7.9A.84.E8.AF.B4.E6.98.8E">修改应用程序用户界面的说明</h2>
<h3 id=".E5.BC.95.E5.AF.BC.E5.9E.8B.E9.99.84.E5.8A.A0.E7.BB.84.E4.BB.B6.E4.B8.AD.E7.9A.84_chrome.manifest">引导型附加组件中的 chrome.manifest</h3>
<p>您可以在引导型附加组件中使用 <a href="/en-US/docs/Chrome_Registration"><code>chrome.manifest</code></a> 文件来:</p>
<ol>
  <li>通过 <code>chrome://</code> URL(在清单(manifest)中使用 <code>content</code>、<code>locale</code> 和 <code>skin</code> 指令)使您的附加组件的内容生效;</li>
  <li>用您的内容替换已经存在的 <code>chrome://</code> URI(使用 <code>override</code> 指令)。</li>
</ol>
<p>不是所有的 <code>chrome.manifest</code> 指令都被引导型附加组件支持,比如在引导型附加组件中,您仍然不能注册 <a href="/en-US/docs/XUL_Overlays">XUL 覆盖界面</a>。详见 <a href="/en-US/docs/Chrome_Registration"><code>chrome.manifest</code></a> 文档。</p>
<p>在 Firefox 10 及以上版本中,放在附加组件 XPI 根目录下的 <code>chrome.manifest</code> 文件(比如与 <code>install.rdf 同级)</code>会被自动加载。在 Firefox 8 和 9 中,您必须手动加载/卸载清单,使用 {{ ifmethod("nsIComponentManager", "addBootstrappedManifestLocation") }} 和 {{ ifmethod("nsIComponentManager", "removeBootstrappedManifestLocation") }}。该特征在 Firefox 8 以前的版本中无效。</p>
<h3 id=".E6.89.8B.E5.8A.A8.E6.B7.BB.E5.8A.A0.E7.94.A8.E6.88.B7.E7.95.8C.E9.9D.A2">手动添加用户界面</h3>
<p>如果您决定继续尝试开发一个修改应用程序用户界面的引导型扩展,这儿有几个建议给您。</p>
<p>您需要在相关应用程序中调用 {{ domxref("document.getElementById()") }},通过 UI 元素的 ID 来查找它们,然后操纵它们来注入您的 UI。例如,您可以通过 <code>document.getElementById("main-menubar") 来访问</code> Firefox 的菜单栏。</p>
<p>确保在关闭时移除您添加的任何用户界面。</p>
<h2 id=".E5.88.9B.E5.BB.BA.E5.BC.95.E5.AF.BC.E5.9E.8B.E6.89.A9.E5.B1.95">创建引导型扩展</h2>
<p>为标示一个扩展为可引导的,您需要添加下列元素到它的<a href="/en-US/docs/Install_Manifests">安装清单</a>:</p>
<pre>
<code>&lt;em:bootstrap&gt;true&lt;/em:bootstrap&gt;</code></pre>
<p>然后您需要添加一个 <a href="/en-US/docs/Extensions/bootstrap.js"><code><strong>bootstrap.js</strong></code> 文件</a>,它包含所要求的函数;在扩展的包中,它应该与 <a href="/en-US/docs/Install_Manifests"><code>install.rdf</code> 文件</a>同级。</p>
<h3 id=".E5.90.91.E5.90.8E.E5.85.BC.E5.AE.B9">向后兼容</h3>
<p>因为旧版本的 Firefox 并不知道 <code>bootstrap</code> 属性或 <code>bootstrap.js</code> 文件,创建一个既能作为可引导扩展又能作为传统扩展来工作的 XPI 并不很困难。按照可引导扩展来创建您的扩展,然后同样地添加传统的覆盖界面。新版本的 Firefox 将使用 <code>bootstrap.js</code> 脚本并忽略部件(components)和覆盖界面,同时旧版本将使用覆盖界面。</p>
<h2 id=".E5.BC.95.E5.AF.BC.E5.88.87.E5.85.A5.E7.82.B9.EF.BC.88entry_points.EF.BC.89">引导切入点(entry points)</h2>
<p><code>bootstrap.js</code> 脚本应该包含几个特殊函数,浏览器调用它们来管理扩展。该脚本被放在一个有特权的(privileged)沙箱中执行,这个沙箱一直被保存(cached)到扩展关闭。</p>
<h3 id="startup">startup</h3>
<p>当扩展需要启动它自己时被调用。它发生在应用程序启动时,或当启用被禁用的扩展时(或在它为了安装更新而被关闭后)。可见,在应用程序的生命期内,它会被多次调用。</p>
<p>您的附加组件应当在这时注入 UI,启动任何可能需要运行的任务,等等。</p>
<pre>
void startup(
&nbsp; data,
&nbsp; reason
); 
</pre>
<h6 id=".E5.8F.82.E6.95.B0">参数</h6>
<dl>
  <dt>
    <code>data</code></dt>
  <dd>
    <a href="#Bootstrap_data">引导数据结构</a>。</dd>
  <dt>
    <code>reason</code></dt>
  <dd>
    <a href="#Reason_constants">原因常量</a>之一,表明为什么扩展被启动。可以是 <code>APP_STARTUP</code>、<code>ADDON_ENABLE、</code><code>ADDON_INSTALL</code>、<code>ADDON_UPGRADE</code> 或 <code>ADDON_DOWNGRADE</code> 之一。</dd>
</dl>
<h3 id="shutdown">shutdown</h3>
<p>当扩展需要关闭它自己时被调用,比如当应用程序退出时,或当即将更新或禁用扩展时。在这里必须移除所有已被注入的用户界面,关闭所有任务,并处理掉所有对象。</p>
<pre>
void shutdown(
&nbsp; data,
&nbsp; reason
);
</pre>
<h6 id=".E5.8F.82.E6.95.B0">参数</h6>
<dl>
  <dt>
    <code>data</code></dt>
  <dd>
    <a href="#Bootstrap_data">引导数据结构</a>。</dd>
  <dt>
    <code>reason</code></dt>
  <dd>
    <a href="#Reason_constants">原因常量</a>之一,表明为什么扩展被关闭。可以是&nbsp;<code>APP_SHUTDOWN</code>、<code>ADDON_DISABLE、ADDON_UNINSTALL、</code><code>ADDON_UPGRADE</code> 或 <code>ADDON_DOWNGRADE</code> 之一。</dd>
</dl>
<h3 id="install">install</h3>
<p>您的引导脚本必须包括 <code>install()</code> 函数,应用程序在安装、升级或降级扩展后,第一次调用 <code>startup()</code> 之前调用它。</p>
<div class="note">
  <strong>注意</strong>:如果从未启动扩展,则不会调用该方法;例如,如果扩展虽被安装但并不兼容当前版本的应用程序,且在变为兼容之前被卸载,则 <code>install()</code> 始终不会被调用。但是,如果扩展被升级到一个兼容应用程序的版本,将在第一次调用 <code>startup()</code> 之前调用它的 <code>install()</code> 函数。</div>
<pre>
void install(
&nbsp; data,
&nbsp; reason
); 
</pre>
<h6 id=".E5.8F.82.E6.95.B0">参数</h6>
<dl>
  <dt>
    <code>data</code></dt>
  <dd>
    <a href="#Bootstrap_data">引导数据结构</a>。</dd>
  <dt>
    <code>reason</code></dt>
  <dd>
    <a href="#Reason_constants">原因常量</a>之一,表明为什么扩展被安装。可以是 <code>ADDON_INSTALL</code>、<code>ADDON_UPGRADE</code> 或 <code>ADDON_DOWNGRADE</code> 之一。</dd>
</dl>
<h3 id="uninstall">uninstall</h3>
<p>该函数在卸载扩展的某个版本之前,最后一次调用 <code>shutdown()</code> 之后被调用。如果始终未调用 <code>install()</code>,也不会调用此函数。</p>
<div class="note">
  <strong>注意:</strong>记住<code>这一点很</code>重要——即使对于当前被禁用或不兼容当前应用程序的扩展,都会被调用 <code>uninstall()</code>。鉴于此,在实现该函数时,优雅地处理那些也许并不存在于应用程序中的 API 变得非常重要。如果一个第三方应用程序在 Firefox 未运行时移除了该扩展,该函数也不会被调用。</div>
<pre>
void uninstall(
&nbsp; data,
&nbsp; reason
); 
</pre>
<h6 id=".E5.8F.82.E6.95.B0">参数</h6>
<dl>
  <dt>
    <code>data</code></dt>
  <dd>
    <a href="#Bootstrap_data">引导数据结构</a>。</dd>
  <dt>
    <code>reason</code></dt>
  <dd>
    <a href="#Reason_constants">原因常量</a>之一,表明为什么扩展被卸载。可以是 <code>ADDON_UNINSTALL</code>、<code>ADDON_UPGRADE</code> 或 <code>ADDON_DOWNGRADE</code> 之一。</dd>
</dl>
<h2 id=".E5.8E.9F.E5.9B.A0.E5.B8.B8.E9.87.8F">原因常量</h2>
<p>上述引导函数都接受一个 <code>reason</code> 参数,该参数向扩展解释为什么调用该函数。 这些原因常量如下:</p>
<table class="standard-table">
  <tbody>
    <tr>
      <td class="header">常量</td>
      <td class="header">值</td>
      <td class="header">描述</td>
    </tr>
    <tr>
      <td><code>APP_STARTUP</code></td>
      <td>1</td>
      <td>应用程序启动。</td>
    </tr>
    <tr>
      <td><code>APP_SHUTDOWN</code></td>
      <td>2</td>
      <td>应用程序关闭。</td>
    </tr>
    <tr>
      <td><code>ADDON_ENABLE</code></td>
      <td>3</td>
      <td>启用附加组件。</td>
    </tr>
    <tr>
      <td><code>ADDON_DISABLE</code></td>
      <td>4</td>
      <td>禁用附加组件。(同时被<a class="link-https" href="https://bugzilla.mozilla.org/show_bug.cgi?id=620541">错用于卸载</a>)</td>
    </tr>
    <tr>
      <td><code>ADDON_INSTALL</code></td>
      <td>5</td>
      <td>安装附加组件。</td>
    </tr>
    <tr>
      <td><code>ADDON_UNINSTALL</code></td>
      <td>6</td>
      <td>卸载附加组件。</td>
    </tr>
    <tr>
      <td><code>ADDON_UPGRADE</code></td>
      <td>7</td>
      <td>升级附加组件。</td>
    </tr>
    <tr>
      <td><code>ADDON_DOWNGRADE</code></td>
      <td>8</td>
      <td>降级附加组件。</td>
    </tr>
  </tbody>
</table>
<h2 id=".E5.BC.95.E5.AF.BC.E6.95.B0.E6.8D.AE">引导数据</h2>
<p>每个切入点被传入一个简单的数据结构,它包含一些关于引导附加组件的有用信息。调用 <code><a href="/en-US/docs/Addons/Add-on_Manager/AddonManager#getAddonByID()">AddonManager.getAddonByID()</a></code> 可以获得更多关于附加组件的信息。该数据是一个简单的 JavaScript 对象,它包括以下属性:</p>
<table class="standard-table">
  <tbody>
    <tr>
      <td class="header">属性</td>
      <td class="header">类型</td>
      <td class="header">描述</td>
    </tr>
    <tr>
      <td><code>id</code></td>
      <td><code>string</code></td>
      <td>被引导附加组件的 ID。</td>
    </tr>
    <tr>
      <td><code>version</code></td>
      <td><code>string</code></td>
      <td>被引导附加组件的版本。</td>
    </tr>
    <tr>
      <td><code>installPath</code></td>
      <td><code>nsIFile</code></td>
      <td>被引导附加组件的安装位置。可能是一个目录或一个 XPI 文件,这取决于安装该附加组件时是否解包。</td>
    </tr>
    <tr>
      <td><code>resourceURI</code></td>
      <td><code>nsIURI</code></td>
      <td>附加组件文件根目录的 URI,可能是 <code>jar:</code> 或 <code>file:</code> URI,这取决于安装该附加组件时是否解包。{{ gecko_minversion_inline("7.0") }}</td>
    </tr>
    <tr>
      <td><code>oldVersion</code></td>
      <td><code>string</code></td>
      <td>以前的安装版本,如果原因是 <code>ADDON_UPGRADE</code> 或 <code>ADDON_DOWNGRADE</code>,并且方法是 <code>install</code> 或 <code>startup</code>。{{ gecko_minversion_inline("22.0") }}</td>
    </tr>
    <tr>
      <td><code>newVersion</code></td>
      <td><code>string</code></td>
      <td>将要安装的版本,如果原因是 <code>ADDON_UPGRADE</code> 或 <code>ADDON_DOWNGRADE</code>,并且方法是 <code>shutdown</code> 或 <code>uninstall</code>。{{ gecko_minversion_inline("22.0") }}</td>
    </tr>
  </tbody>
</table>
<div class="note">
  <p><strong>注意:</strong>附加组件可能会在程序启动时升降级,此时 <code>startup</code> 方法的原因是 <code>APP_STARTUP</code>,并且不会设置 <code>oldVersion</code> 属性。 另外需注意,在某些情形下有可能发生附加组件升降级但 <code>uninstall</code> 方法没有被调用的情况。</p>
</div>
<h2 id=".E5.BB.B6.E4.BC.B8.E9.98.85.E8.AF.BB">延伸阅读</h2>
<ul>
  <li>Wladimir Palant 解释了<a class="external" href="http://adblockplus.org/blog/how-many-hacks-does-it-take-to-make-your-extension-install-without-a-restart">转化已存在的扩展时发现的问题和漏洞</a>,包括一些解决方案和变通方法。</li>
  <li>Mark Finkle 为<a class="external" href="http://starkravingfinkle.org/blog/2011/01/bootstrap-jones-adventures-in-restartless-add-ons/">移动 Firefox 中无需重启的附加组件</a>提供了一些简单示例代码,向引导型扩展<a class="external" href="http://starkravingfinkle.org/blog/2011/01/restartless-add-ons-more-resources/">添加资源(如选项窗口)</a>,<a class="external" href="http://starkravingfinkle.org/blog/2011/01/restartless-add-ons-%e2%80%93-default-preferences/">使用默认参数</a>而不使用 <code>default/preferences/prefs.js</code> 文件。</li>
  <li>Kris Maglione 写的关于在引导型扩展中<a class="external" href="http://maglione-k.users.sourceforge.net/bootstrapped.xhtml">清理程序的要求</a>。</li>
  <li>Edward Lee 炫耀了一些<a class="external" href="http://ed.agadak.net/2011/01/restartless-add-on-example-code">有用的编码模式和示例</a>,您可以用于您的引导型附加组件。</li>
  <li>Erik Vold 的关于无需重启附加组件的快速指南:
    <ul>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2010/11/3/restartless-restart-addon-for-firefox">第一部分:简介</a></li>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2011/1/2/restartless-firefox-addons-part-2-includes">第二部分:包含(includes)</a></li>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2011/2/7/restartless-firefox-addons-part-3-icons">第三部分:图标</a></li>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2011/2/18/restartless-firefox-addons-part-4-localization-l10n">第四部分:本地化(l10n)</a></li>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2011/4/1/restartless-firefox-addons-part-5-logging">第五部分:日志</a></li>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2011/6/14/restartless-firefox-addons-part-6-better-includes">第六部分:更好地包含</a></li>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2011/6/19/restartless-firefox-addons-part-7-css">第七部分:CSS</a></li>
      <li><a class="external" href="http://erikvold.com/blog/index.cfm/2011/6/19/restartless-firefox-addons-part-8-require-commonjs-and-jetpack">第八部分:要求(Require)、CommonJS 和 Jetpack</a></li>
    </ul>
  </li>
  <li>Firefox 7 及以上版本中<a href="/en-US/docs/Extensions/Inline_Options">内联选项(Inline Options)</a>的文档。</li>
</ul>
恢复到这个版本