文档章节

基于Chrome的扩展开发(一)

小编辑
 小编辑
发布于 2010/01/26 03:16
字数 1230
阅读 605
收藏 1

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

本文转载自:http://www.cnblogs.com/phinecos/archive/2009/03/19/1417028.html

共有 人打赏支持
小编辑

小编辑

粉丝 1361
博文 44
码字总数 4847
作品 0
广州
网页/平面设计
私信 提问
离线Chrome插件安装文件(crx)的安装方法

离线Chrome插件安装文件(crx)的安装方法 一、正常安装方法 1.开发谷歌浏览器,设置->扩展程序 在打开的谷歌浏览器的扩展管理器中用户可以看到一些已经安装程序的Chrome插件,或者一个Chrom...

曾将
2018/07/10
0
0
【教程】CRX格式插件不能离线安装?本地扩展CRX无法安装怎么办?

最近有很多用户反映有一些Chrome插件在离线安装的时候,根据本站的教程:离线安装CRX格式chrome插件的方法。无法正常完成安装,提示“只能通过Chrome网上应用商店安装该程序”,小编为了了解...

CS青雀
02/21
0
0
新扩展可让Chrome 支持ActiveX

ActiveX控件的强制捆绑使国内的网银只能在IE或基于IE内核的浏览器上登陆,此次的Chrome浏览器上的ActiveX扩展让我们看到了 在非IE浏览器上使用网银的希望ActiveX 是一个开放的集成平台,为开...

红薯
2011/03/21
14.5K
11
手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单

手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩展二:为html添加行为 手把手教你开发Chrome扩展三:关于本地存储数据 Chrome的更新速度可以说前无古人...

Ryan-瑞恩
2012/12/22
0
0
Linux、Mac版Chrome 4.0 Beta首登场

几经等待后Google终于在今天为Mac和Linux平台提供了Chrome浏览器,虽然仍处于Beta测试阶段,不过作为首个官方正式发布的Beta版本,这两个版本的发布为Chrome向跨平台多元用户的发展提供了更好...

红薯
2009/12/09
401
3

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周四乱弹 —— Im fine

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @LuckyXu:分享戴荃的单曲《小荃拳之歌》: 手机党少年们想听歌,请使劲儿戳(这里) 今天遇到倒霉事了, @ FalconChen :电梯宕机了我靠 但是...

小小编辑
16分钟前
9
4
【转载】uclibc和glibc的差别

转载自:http://blog.163.com/huangnan0727@126/blog/static/30626184201042022011225/ CC的标准库,就是glibc这个库,里面有GCC各种标准函数的实现,还有各种unix系的函数在里面。 当初创建...

shzwork
25分钟前
0
0
关于360插件化Replugin Activity动态修改父类的字节码操作

近期在接入360插件化方案Replugin时,发现出现崩溃情况。 大概崩溃内容如下: aused by: java.lang.ClassNotFoundException: Didn't find class "x.x.x.xActivity" on path: 我自己在插件代码......

Gemini-Lin
今天
1
0
mybatis缓存的装饰器模式

一般在开发生产中,对于新需求的实现,我们一般会有两种方式来处理,一种是直接修改已有组件的代码,另一种是使用继承方式。第一种显然会破坏已有组件的稳定性。第二种,会导致大量子类的出现...

算法之名
昨天
21
0
单元测试

右键方法 Go To --> Test,简便快速生成测试方法。 相关注解 @RunWith(SpringRunner.class) 表示要在测试环境中跑,底层实现是 jUnit测试工具。 @SpringBootTest 表示启动整个 Spring工程 @A...

imbiao
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部