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