概述

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

基础

应用由一些文件(包括 HTML、CSS、JavaScript、图片以及其他任何您需要的文件)经过 zip 打包得到,为百度浏览器增加功能。应用本质上是网页,它们可以利用浏览器为网页提供的所有 API,例如 XMLHttpRequest、JSON、HTML 5 等等。

应用可以通过内容脚本跨域 XMLHttpRequest 与网页或者服务器交互,应用也可以以编程方式与浏览器功能

应用的用户界面

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

screenshot screenshot screenshot
这一Google Mail Checker 应用使用浏览器按钮(工具栏中的图标)。 这一Mappy 应用使用页面按钮(地址栏中的图标)以及内容脚本(插入网页的代码)。 单击时显示弹出菜单的浏览器按钮是这一新闻阅读器应用的特色。

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

文件

每一个应用包含以下文件:

  • 一个清单文件
  • 一个或多个 HTML 文件(除非应用是一个主题背景)
  • 可选:一个或多个 JavaScript 文件
  • 可选:您的应用需要的任何其他文件,例如图片

当您编写您的应用时,您将所有这些文件放在一个文件夹中。当您发布您的应用时,该文件夹的内容将被压缩成一个特殊的 ZIP 文件,以 .crx 为后缀。

引用文件

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

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

您使用百度浏览器的调试器时可能会发现,应用中的每一个文件也可以通过绝对 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 文件实现。 最后,您可以使用 tabs.createwindow.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 外,还能使用仅用于百度浏览器的 API(通常称为 chrome.* API)来更好地与浏览器集成。例如,任何应用或网上应用可以使用标准的 window.open() 方法来打开一个网页,但是如果您想指定网页应该显示在哪个窗口中,您的应用就可以使用仅用于百度浏览器的 tabs.create 方法。

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

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

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

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

string chrome.runtime.getURL()

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

例子:使用回调函数

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

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

//以下代码不能正常工作!
var tab = chrome.tabs.query({'active': true}); //错误!
chrome.tabs.update(tab.id, {url:newUrl});
someOtherFunction();

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

chrome.tabs.query(object queryInfo, function callback)

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

//以下代码可以正常工作
chrome.tabs.query({'active': true}, function(tabs) {
  chrome.tabs.update(tabs[0].id, {url: newUrl});
});
someOtherFunction();

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

更多详情

有关更多信息,请参见 chrome.* API 文档

页面间的通信

应用中的 HTML 网页通常需要通信。因为一个应用的所有网页在同一个进程中的同一个线程上执行,网页之间可以直接调用函数。

要获得应用中的网页,请使用 chrome.extension 方法,例如 extension.getViewsextension.getBackgroundPage。一旦一个网页引用了应用中的其他网页,第一个网页可以执行其他网页上的函数,并且可以操纵它们的 DOM。

保存数据和隐身模式

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

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

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

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

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

现在做什么呢?

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