基于Chrome的扩展开发(一)

Google终于放出了Chrome的第一个扩展示例,虽然还十分简陋,但对喜欢扩展的firefox粉丝来说可说是个大好消息。

准备工作:你需要使用a recent developer build 或者Google Chrome 2.0 beta.

1)首先创建一个文件夹,例如c:"myextension,在这个目录下创建一个文本文件,命名为manifest.json,在其中放入下面几句:
{
  "format_version": 1,
  "id": "00123456789ABCDEF0123456789ABCDEF0123456",
  "version": "1.0",
  "name": "My First Extension",
  "description": "The first extension that I made."
}

其中各个参数含义如下:

format_version(必需的):向Chrome指明扩展所使用的清单格式版本。目前只有一个格式版本,因此设为1.

id(必需的):扩展的ID号(唯一的)。目前可以设为任何40个十进制数字,将来会改为扩展的公钥的SHA-1的哈希值。

version(必需的):扩展的版本号。可以使用任意点分格式的数字串

name(必需的):扩展的名称。

description(可选的):扩展的描述信息

2)在目录下加入一个hello_world.html文件,在其中加入
    Hello,  World!

3)为了让Chrome支持扩展,右键桌面上Chrome的快捷键,选择“属性”,在“目标”这一栏中空一格后,加入
--enable-extensions --load-extension="c:\myextension"

 

4)启动Chrome,输入下列URL:
chrome-extension://00123456789ABCDEF0123456789ABCDEF0123456/hello_world.html

如图所示:

 

5)输入下列URL:
chrome-ui://extensions/

将会列出所有已经安装的扩展,同时还会显示扩展系统启动时发生的错误信息。

 

6)内容脚本。它是由Chrome加载进来在web页面上运行的JavaScript文件。这和firefox扩展类似。要加入一个内容脚本,首先在清单文件中对其进行注册,如下所示:
{
  "format_version": 1,
  "id": "00123456789ABCDEF0123456789ABCDEF0123456",
  "version": "1.0",
  "name": "My First Extension",
  "description": "The first extension that I made.",
  "content_scripts": [
    {
      "matches": ["http://www.google.com/*"],
      "js": ["foo.js"]
    }
  ]
}

      然后创建一个脚本文件foo.js,其中代码如下:
document.images[0].src = "http://bit.ly/1293Af";
document.images[0].style.height = "auto";

     在Chrome中输入http://www.google.com/,你将看到如下画面:

 

注:内容脚本可以在页面开头或结尾执行,默认情况下是结尾处执行,当然你也可以加入”run_at”:”document-start”来告诉Chrome在开头处执行。

7)NPAPI插件。Chrome扩展可以包含NPAPI插件这样的二进制组件。如果你想在扩展中使用一个NPAPI插件,首先在扩展中为其创建一个目录,名为”plugins”,然后在清单文件中为其注册如下:
{
  "format_version": 1,
  "id": "00123456789ABCDEF0123456789ABCDEF0123456",
  "version": "1.0",
  "name": "My First Extension",
  "description": "The first extension that I made.",
  "plugins_dir": "plugins"
}

8)打包发布。要对扩展进行打包发布前,首先确认你安装了Python2.6,然后使用下述脚本文件chromium_extension.py
chromium_extension.py
#!/usr/bin/python
# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# chromium_extension.py

import array
import hashlib
import logging
import optparse
import os
import re
import shutil
import sys
import zipfile

if sys.version_info < (2, 6):
  import simplejson as json
else:
  import json


ignore_dirs = [".svn", "CVS"]
ignore_files = [re.compile(".*~")]

MANIFEST_FILENAME = "manifest.json"

class ExtensionDir:
  def __init__(self, path):
    self._root = os.path.abspath(path)
    self._dirs = []
    self._files = []
    for root, dirs, files in os.walk(path, topdown=True):
      for dir in ignore_dirs:
        if dir in dirs:
          dirs.remove(dir)
      root = os.path.abspath(root)
      for dir in dirs:
        self._dirs.append(os.path.join(root, dir))
      for f in files:
        for match in ignore_files:
          if not match.match(f):
            self._files.append(os.path.join(root, f))

  def validate(self):
    if os.path.join(self._root, MANIFEST_FILENAME) not in self._files:
      logging.error("package is missing a valid %s file" % MANIFEST_FILENAME)
      return False
    return True

  def writeToPackage(self, path):
    if not self.validate():
      return False
    try:
      f = open(os.path.join(self._root, MANIFEST_FILENAME))
      manifest = json.load(f)
      f.close()

      zip_path = path + ".zip"
      if os.path.exists(zip_path):
        os.remove(zip_path)
      zip = zipfile.ZipFile(zip_path, "w")
      (root, dir) = os.path.split(self._root)
      root_len = len(self._root)
      for file in self._files:
        arcname = file[root_len+1:]
        logging.debug("%s: %s" % (arcname, file))
        zip.write(file, arcname)
      zip.close()

      zip = open(zip_path, mode="rb")
      hash = hashlib.sha256()
      while True:
        buf = zip.read(32 * 1024)
        if not len(buf):
          break
        hash.update(buf)
      zip.close()

      manifest["zip_hash"] = hash.hexdigest()

      # This is a bit odd - we're actually appending a new zip file to the end
      # of the manifest.  Believe it or not, this is actually an explicit
      # feature of the zip format, and many zip utilities (this library
      # and three others I tried) can still read the underlying zip file.
      if os.path.exists(path):
        os.remove(path)
      out = open(path, "wb")
      out.write("Cr24")  # Extension file magic number
      # The rest of the header is currently made up of three ints:
      # version, header size, manifest size
      header = array.array("l")
      header.append(1)  # version
      header.append(16)  # header size
      manifest_json = json.dumps(manifest);
      header.append(len(manifest_json))  # manifest size
      header.tofile(out)
      out.write(manifest_json);
      zip = open(zip_path, "rb")
      while True:
        buf = zip.read(32 * 1024)
        if not len(buf):
          break
        out.write(buf)
      zip.close()
      out.close()

      os.remove(zip_path)

      logging.info("created extension package %s" % path)
    except IOError, (errno, strerror):
      logging.error("error creating extension %s (%d, %s)" % (path, errno,
                    strerror))
      try:
        if os.path.exists(path):
          os.remove(path)
      except:
        pass
      return False
    return True


class ExtensionPackage:
  def __init__(self, path):
    zip = zipfile.ZipFile(path)
    error = zip.testzip()
    if error:
      logging.error("error reading extension: %s", error)
      return
    logging.info("%s contents:" % path)
    files = zip.namelist()
    for f in files:
      logging.info(f)


def Run():
  logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")

  parser = optparse.OptionParser("usage: %prog --indir=<dir> --outfile=<file>")
  parser.add_option("", "--indir",
                    help="an input directory where the extension lives")
  parser.add_option("", "--outfile",
                    help="extension package filename to create")
  (options, args) = parser.parse_args()
  if not options.indir:
    parser.error("missing required option --indir")
  if not options.outfile:
    parser.error("missing required option --outfile")
  ext = ExtensionDir(options.indir)
  ext.writeToPackage(options.outfile)
  pkg = ExtensionPackage(options.outfile)
  return 0


if __name__ == "__main__":
  retcode = Run()
  sys.exit(retcode)

 这个脚本运行方式如下所示:
chromium_extension.py --indir="c:\myextension" --outfile="myextension.crx"

这将会产生一个.crx文件,然后将其拖拽进Chrome即可实现扩展的安装

参考资料

1Chrome Extension HOWTO

2First Google Chrome Extensions

你可能感兴趣的:(基于Chrome的扩展开发(一))