chrome插件中文开发文档(非官方)

概述

当您看完该页面以及 入门 教程后,您已经准备好开始编写扩展程序和打包应用程序了。

基础

扩展程序由一些文件—HTML、CSS、JavaScript、图片以及其它任何您需要的文件— 为Google Chrome浏览器增加功能 扩展程序本质上是网页,它们可以利用 浏览器为网页提供的所有API, 例如XMLHttpRequest、JSON、HTML5等等。

扩展程序可以通过 内容脚本 or 跨站XML请求. 与网页或者服务器交互,扩展程序也可以以编程方式与浏览器功能交互,例如 书签标签页.

扩展程序的用户界面

许多扩展程序—但不包括打包应用程序—以 浏览器按钮页面按钮. 的形式向Google Chrome浏览器增加用户界面,每个扩展程序最多能有一个浏览器按钮或页面按钮。当扩展程序与大部分网页相关时选择使用 浏览器按钮 ,当扩展程序的图标显示还是消失取决于具体网页时选择使用 页面按钮

screenshot screenshot screenshot
这一 邮件扩展程序 使用 浏览器按钮 (工具栏中的图标). 这一 地图扩展程序 使用 页面按钮 (地址栏中的图标) 以及 内容脚本 (插入网页的代码). 单击时弹出内容 弹出内容是这一 新闻扩展程序 的特色。

扩展程序(以及打包应用程序)也可以以其它形式呈现用户界面,例如在Chrome浏览器的右键菜单中添加内容,提供选项页面,或者利用内容脚本更改页面的显示方式。有关完整的扩展程序功能以及每一种功能的实现细节,请参见 开发者指南

文件

每一个扩展程序包含以下文件:

当您编写您的扩展程序时,您将所有这些文件放在一个文件夹中。当您发布您的扩展程序时,该文件夹的内容将被压缩成一个特殊的ZIP文件,以 .crx 为后缀 如果您通过 Chrome开发者信息中心, 上传您的扩展,该 .crx文件是自动为您创建的。 有关发布扩展的细节,参见托管.

引用文件

您可以在扩展程序中放置任何您需要的文件,但是您如何使用它们呢?通常,您可以通过相对URL引用文件,就像在普通的HTML页面中那样。下面是一个例子,引用位于子文件夹 images中名为 myimage.png 的文件。

<img src="images/myimage.png">

您使用Google Chrome浏览器的调试器时可能会发现,扩展程序中的每一个文件也可以通过绝对URL访问,就像这样:

chrome-extension://<扩展程序唯一标识符>/<文件路径>

在这一URL中, <扩展程序唯一标识符>是扩展程序系统为每一个扩展程序生成的唯一标识符,您可以进入 chrome://extensions查看您载入的所有扩展的唯一标识符。 <文件路径> 是扩展程序的主目录下的文件位置,与相对URL相同。

当您编写扩展程序时(打包之前),扩展程序唯一标识符可以更改。特别地,如果您从另一个目录载入未打包的扩展程序,它的唯一标识符会改变,当您打包扩展程序时会再次改变。如果您的扩展程序代码需要指定扩展程序中某个文件的完整路径,您可以使用 @@extension_id这一 预定义消息 ,避免开发过程中硬编码唯一标识符。

当您打包扩展程序时(典型情况下,通过信息中心上传),该扩展程序将会获得一个永久的唯一标识符,即使您更新了这一扩展程序仍然保持不变。一旦扩展程序唯一标识符变成永久的了,您就可以将所有 的@@extension_id修改为真正的唯一标识符。

清单文件

清单文件,名为manifest.json, 提供有关扩展程序的各种信息,例如最重要的文件和扩展程序可能具有的能力。以下是一个典型的清单文件,用于一个浏览器按钮,它将会访问来自google.com的信息:

{
  "name": "我的扩展程序",
  "version": "2.1",
  "description": "从Google获得信息。",
  "icons": { "128": "icon_128.png" },
  "background": {
    "persistent": false,
    "scripts": ["bg.js"]
  },
  "permissions": ["http://*.google.com/", "https://*.google.com/"],
  "browser_action": {
    "default_title": "",
    "default_icon": "icon_19.png",
    "default_popup": "popup.html"
  }
}

有关更多细节,请参见 清单文件.

架构

许多扩展程序有一个后台页面, 它是一个包含扩展程序主要逻辑的不可见页面。扩展程序也可以包含其它页面,展现扩展程序的用户界面。如果扩展程序需要与用户载入的网页交互(相对于包含在扩展程序中的页面),扩展程序必须使用内容脚本

后台页面

下图所示的浏览器至少安装了两个扩展程序:一个浏览器按钮(黄色图标)和一个页面按钮(蓝色图标)。浏览器按钮和页面按钮都有后台页面。下图显示了浏览器按钮的后台页面,由 background.html 定义,并且包含在这两个窗口中控制浏览器按钮的JavaScript代码。

Two windows and a box representing a background page (background.html). One window has a yellow icon; the other has both a yellow icon and a blue icon. The yellow icons are connected to the background page.

后台页面分两种: 持久运行的后台页面, 与事件页面。 正如其名字所说,持续运行的后台页面保持打开状态;事件页面根据需要打开与关闭。除非您绝对需要您的后台页面一直运行,请首选事件页面。

有关更多详情,请参见事件页面后台页面

用户界面页面

扩展程序可以包含普通的HTML页面,用来显示扩展程序的用户界面。例如,浏览器按钮可以包含弹出内容,通过HTML文件实现。任何一个扩展程序都可以有选项页面,让用户自定义扩展程序的工作方式。另外一种特殊页面是替代页面。最后,您可以使用 chrome.tabs.create()window.open() 来显示扩展程序中的任何其它HTML文件。

扩展程序中的HTML页面可以互相访问其它页面的全部DOM,并且可以互相调用函数。

下图显示了浏览器按钮弹出内容的架构。弹出内容是由一个HTML文件 (popup.html). 定义的网页,该扩展程序也正好有一个后台页面 (background.html)。 弹出窗口不用重复后台页面中的代码,因为弹出窗口可以调用后台页面上的函数。

A browser window containing a browser action that's displaying a popup. The popup's HTML file (popup.html) can communicate with the extension's background page (background.html).

有关更多细节,请参见浏览器按钮, 选项, 替代页面, 和页面间通信这些部分。

内容脚本

如果您的扩展程序需要与网页交互,您就需要使用内容脚本。 内容脚本是一些JavaScript代码,它们在浏览器中已载入页面的上下文中执行。您应该将内容脚本视为已载入页面的一部分,而不是打包在一起的扩展程序 (它所属的扩展程序).的一部分。

内容脚本可以读取浏览器访问的网页的细节,并且可以修改页面。在下图中,内容脚本可以读取并且修改显示的网页的DOM。然而,它不能修改所属扩展程序的后台页面的DOM。

A browser window with a browser action (controlled by background.html) and a content script (controlled by contentscript.js).

内容脚本并不是完全与所属扩展程序隔离的。内容脚本可以与所属扩展程序交换消息,如下图箭头所示。例如,每当在浏览器页面中发现RSS供稿时,内容脚本可以发送消息,反过来后台页面也可以发送消息要求内容脚本更改浏览器页面的外观。

Like the previous figure, but showing more of the parent extension's files, as well as a communication path between the content script and the parent extension.

有关更多信息,请参见内容脚本

使用chrome.* API

扩展程序除了能够使用网页和应用程序可以使用的所有API外,还能使用仅用于Chrome浏览器的API(通常称为 chrome.* APIs) 来更好地与浏览器集成。例如,任何扩展程序或网上应用程序可以使用标准的 window.open()方法来打开一个网页,但是如果您想指定网页应该显示在哪个窗口中,您的扩展程序就可以使用仅用于Chrome浏览器的 chrome.tabs.create() 方法。

异步方法与同步方法的区别

大部分chrome.* API的方法都是异步的: 它们不等待操作完成就立即返回。如果您需要知道操作结果,您可以向方法传递一个回调函数,回调函数将稍后执行(可能 很久 之后), 在方法返回后的某个时刻。下面是一个异步方法签名的例子:

chrome.tabs.create(object createProperties, function callback)

少数chrome.*方法是同步的。 同步的方法没有回调参数,因为它们只有当所有操作完成后才返回。通常,同步方法有返回值类型。考虑 chrome.runtime.getURL()方法:

string chrome.runtime.getURL()

该方法没有回调参数,但是有返回值类型string ,因为它同步地返回URL,不进行任何其它异步操作。

例子:使用回调函数

假设您想在用户当前选定的标签页中打开新的页面。要想这么做,您首先需要获得当前标签页的唯一标识符(使用 chrome.tabs.getSelected()) ,然后使该标签转到指定的新的URL(使用 chrome.tabs.update())。

假如getSelected()是同步的,您可能会写这样的代码:

   //以下代码不能正常工作
1: var tab = chrome.tabs.getSelected(null); //错误!!!
2: chrome.tabs.update(tab.id, {url:newUrl});
3: someOtherFunction();

这样的方法不行,因为getSelected() 是异步的。 它不等待操作完成就返回了,并且它事实上都不返回任何值(尽管有些异步方法会返回信息)。您可以通过它签名中的callback参数看出 getSelected()是异步的:

chrome.tabs.getSelected(integer windowId, function callback)

要改正上面的代码,您必须使用那个回调参数。以下代码显示如何定义一个回调函数,从 getSelected() 获得结果(通过名为tab的参数) 并调用update()

   //以下代码可以正常工作
1: chrome.tabs.getSelected(null, function(tab) {
2:   chrome.tabs.update(tab.id, {url:newUrl});
3: });
4: someOtherFunction();

在这一例子中,以上几行是按照这样的顺序执行的:1、4、2。只有在有关当前选定标签的信息可用后,即 getSelected返回后的某一时刻,才调用在 getSelected()中指定的回调函数(并且执行第二行)。尽管 update()是异步的,这一例子没有使用回调参数,因为我们对于调用的结果并不感兴趣。

更多细节

有关更多信息,请参见 chrome.* API 文档 并观看以下视频(英文):

页面间的通信

扩展程序中的HTML页面通常需要通信。因为一个扩展程序的所有页面在同一个进程中的同一个线程上执行,页面可以直接互相调用函数。

要获得扩展程序中的页面,使用 chrome.extension 方法,例如 getViews()getBackgroundPage() 。一旦一个页面引用了扩展程序中的其它页面,第一个页面可以执行其它页面上的函数,并且可以操纵它们的DOM。

保存数据和隐身模式

扩展程序可以使用HTML5网页存储API (例如localStorage) 或者向服务器发出请求保存数据。每当您要保存任何数据前,首先考虑是否来自隐身窗口。默认情况下,扩展程序不在隐身窗口中运行,但是打包应用程序会在隐身窗口中运行。当浏览器处于隐身模式时,您需要考虑用户对您的扩展程序或打包应用程序的需求。

隐身模式确保不会留下任何痕迹。当处理来自隐身窗口的数据时,尽可能地遵守这一约定。例如,如果您的扩展程序通常将浏览器历史记录保存至云端,不要保存来自隐身窗口的历史记录。另一方面,您可以在任何窗口中保存您的扩展程序设置,无论隐身与否。

准则: 如果某些数据可能显示用户在网上的访问记录或者用户所做的事情,千万不要保存来自隐身窗口的这些数据。

要确定窗口是否处于隐身模式,检查相关的 TabWindow对象的 icognito属性。例如:

function saveTabData(tab, data) {
  if (tab.incognito) {
    chrome.runtime.getBackgroundPage(function(bgPage) {
      bgPage[tab.url] = data;      // 仅留在内存中的数据
    });
  } else {
    localStorage[tab.url] = data;  // 可以保存数据
  }
}

现在做什么呢?

现在您已经大致了解扩展程序了,您应该准备好编写您自己的扩展了。您接下来可以参考以下内容: