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:
如图所示:
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= --outfile=")
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即可实现扩展的安装
参考资料
1,Chrome Extension HOWTO
2,First Google Chrome Extensions