背景

WebExtensions 在一个沙盒环境中运行,类似于常规网页内容。扩展的目的是以常规内容无法实现的方式增强浏览器——WebExtensions API 通过以一种保持安全、可靠性和性能的方式向扩展公开浏览器功能来弥合这一差距。WebExtension API 的实现使用 chrome 权限 运行。浏览器内部通过 XPCOMChromeOnly WebIDL 功能 访问。

本文档的其余部分介绍了 API 实现如何与 WebExtensions 的实现交互。要将某些浏览器功能公开给 WebExtensions,第一步是设计 API。API 设计的一些高级原则记录在 Mozilla wiki 上

Javascript API

许多 WebExtension API 是通过 Javascript 直接从扩展访问的。函数是公开的最常见类型的对象,尽管一些扩展公开了基本 Javascript 类型(例如,常量)的属性。无论使用哪种确切的方法公开某些内容,在设计 Javascript 可访问的 API 部分时,都有一些重要的注意事项

  • 命名空间:提供给扩展的所有内容都作为名为 browser 的全局对象的一部分公开。为了与 Google Chrome 保持兼容性,许多这些功能也公开在名为 chrome 的全局对象上。函数和其他对象不会直接作为 browser 上的属性公开,它们被组织成命名空间,这些命名空间显示为 browser 上的属性。例如,选项卡 API 使用名为 tabs 的命名空间,因此其所有函数和其他属性都显示在对象 browser.tabs 上。对于通过 Javascript 提供功能的新 API,通常的做法是创建一个具有简洁但描述性名称的新命名空间。

  • 环境:扩展代码可以执行的 Javascript 环境有几种不同类型:扩展页面、内容脚本、代理脚本和开发者工具页面。扩展页面包括后台页面、弹出窗口和通过 browser.runtime.getURL() 访问的内容页面。在创建新的 Javascript 功能时,设计人员必须选择在这些环境中的哪个环境中提供该功能。大多数 Javascript 功能在扩展页面中可用,其他环境可用的 API 功能集有限。

  • 权限:许多 Javascript 功能仅适用于扩展清单中包含相应权限的扩展。API 功能何时需要权限的指南在(需要引用)中进行了描述。

可以通过 Javascript 公开的特定类型的功能有

  • 函数:从 Javascript 可调用的函数可能是 WebExtension API 中最常用的功能。新的 API 函数是异步的,返回一个 Promise。即使不返回值的函数也使用 Promise,以便可以通过拒绝的 Promise 异步指示错误,而不是同步抛出错误。这是因为扩展在子进程中运行,并且许多 API 函数需要与主进程通信。如果需要以这种方式进行通信的 API 函数返回同步结果,那么子进程中的所有 Javascript 执行都需要暂停,直到收到来自主进程的响应。即使函数可以在子进程中同步实现,标准做法也是将其设为异步,以避免限制底层浏览器功能的实现,并使其无法将功能移出子进程。函数使用进程间通信的另一个结果是,函数的参数及其返回值都必须是可以通过使用 结构化克隆算法 在进程之间发送的简单数据类型。

  • 事件:事件通过允许浏览器中的事件在扩展中调用回调来补充函数(允许扩展调用 API)。每当 API 需要扩展传递一个在任意次数被调用的回调函数时,该 API 方法都应定义为事件。

清单键

除了通过 Javascript 提供功能外,WebExtension API 还可以根据扩展清单中特定属性的内容(甚至只是特定属性的存在)采取操作。清单条目用于扩展在安装或启动时指定某些静态信息的功能(即,在有机会运行任何代码以使用 Javascript API 之前)。API 可能会处理清单键并实现 Javascript 功能,请参阅 浏览器操作 API 以获取示例。

其他注意事项

除了上面概述的指南外,在设计和实现 WebExtension API 时还需要考虑一些其他事项

  • 清理:编写不当的 WebExtension 不应该能够永久泄漏任何资源。特别是,扩展发出的导致在浏览器中分配资源的任何操作都应在扩展被禁用或卸载时自动清理。这在有关 管理扩展生命周期 的部分中有更详细的说明。

  • 性能:新的 WebExtension API 在不使用该 API 时不应向浏览器添加任何新的开销。也就是说,除非扩展主动使用 API,否则 API 的实现根本不应该加载。此外,应尽可能延迟初始化——扩展在浏览器启动过程的相对较早的阶段启动,因此在扩展启动期间完成的任何不必要的工作都会直接导致浏览器启动缓慢。