Chrome extension features

Chrome浏览器一个非常厉害的地方是建立了一个强大的extension系统,提供了丰富的浏览器extension接口。我们打开Chrome网上应用商店https://chrome.google.com/webstore/category/extensions,可以看到第三方开发者用这些extension接口做出各种各样的扩展程序,比如广告过滤、视频下载等等。 Chrome的extension系统提供的extension接口在Chrome的代码实现里称之为“extension features”,我这篇博客不是介绍如何使用Chrome的extension接口开发一个extension程序,而是介绍extension features的一些基础知识。

feature files

extension feature不仅仅包括了extension的api,还包括了结构和行为的定义。feature files指定了不同的extension feature可用性的要求。目前用到了4种feature files:

Simple and Complex Features

Feature还可以分为simple(简单)和complex(复杂)两种。一般都是simple feature,如下所示:

"feature1": {
  "dependencies": ["permission:feature1"],
  "contexts": ["blessed_extension"]
}

Complex feature是有多个定义的,如下所示:

"feature1": [{
  "dependencies": ["permission:feature1"],
  "contexts": ["blessed_extension"]
}, {
  "dependencies": ["permission:otherPermission"],
  "contexts": ["blessed_extension", "unblessed_extension"]
}]

Complex feature满足任意一个定义就可用。不过应该避免使用Complex feature也,这会增加复杂度和执行速度变慢。

feature定义的继承性

定义一个feature1.child的feature,那么child是feature1的子类,默认的子类会继承父类属性。如下所示:

"feature1": {
  "dependencies": ["permission:feature1"],
  "contexts": ["blessed_extension"]
},
"feature1.child": {
  "contexts": ["unblessed_extension"],
  "extension_types": ["extension"]
}

那么feature1.child最终的属性是:

"dependencies": ["permission:feature1"], # 继承自 feature1的属性
"contexts": ["unblessed_extension"],     # 子类覆盖父类的同名属性
"extension_types": ["extension]          # 子类自己独有的属性

如果父类不想子类继承自己的属性,则显示给自己加上”noparent”: true的属性值。 如果父类是一个complex feature,有多个定义,可以在某个定义加上”default_parent”: true属性值,那么子类就继承父类这个定义的属性。

属性

下面介绍一下feature的一些属性。

alias

这个属性是给feature定义一个别名,用的很少。

blacklist

blacklist属性指定了extension id哈希值的列表,在列表中的entension都不能使用该feature。 比如一个id为aaaabbbbccccddddeeeeffffgggghhhh的extension,它的extension id的哈希值为:9A0417016F345C934A1A88F55CA17C05014EEEBA python的计算逻辑如下:

import hashlib

data = b'aaaabbbbccccddddeeeeffffgggghhhh'
hash_str = hashlib.sha1(data).hexdigest()
print(hash_str.upper())

channel

feature支持的最大浏览器channel。channel的值从下到大依次是trunk、canary、 dev、beta、stable。如下所示:

  "identity.getAccounts": {
    "channel": "dev",
    "dependencies": ["permission:identity"],
    "contexts": ["blessed_extension"]
  },

identity.getAccounts的的channel值是dev,则意味着该feature只能在trunk、canary、dev中使用。

command_line_switch

指定启用该feature,浏览器必须具有的命令行开关。这个属性用的也不多,有个具体例子:

  "experimental": {
    "channel": "stable",
    "command_line_switch": "experimental-extension-apis",
    "extension_types": [
      "extension", "legacy_packaged_app", "hosted_app", "platform_app"
    ]
  },

上面feature定义说明了,如果experimentalfeature启用,则浏览器必须有experimental-extension-apis命令行参数。

contexts

指定哪种javascript context可以访问该feature。所有的api类型feature必须指定一种content,也只有api类型feature可以有这个属性。 context有以下几种类型:

default_parent

complex feature指定默认的父类,好让子类知道该从哪个父类定义中继承属性。

dependencies

该属性指定本feature依赖的其他feature。 一般惯例是把尽可能多的限制放到permission和manifest feature里面,让我们在加载extension的时候就发出警告。把相对少的限制放到api feature里面,并让api feature依赖permission和manifest feature。

extension_types

feature允许的extension的类型,有以下值:extension、hosted_app、legacy_packaged_app、platform_app、shared_module、and theme。

internal

表示该feature只能在Chromium内部中使用。

matches

设置url通配符,符合才能访问该feature。如下:

  "quickUnlockPrivate": {
    "channel": "stable",
    "contexts": ["webui"],
    "matches": [
      "chrome://md-settings/*",
      "chrome://settings/*",
      "chrome://settings-frame/*"
    ],
    "platforms": ["chromeos"]
  },

表示只有匹配上chrome://md-settings/或chrome://settings/或chrome://settings-frame/*的url可以访问该feature。

noparent

让子类不继承父类的属性。

platforms

feature支持的平台,有以下值:chromeos、mac、linux、win。

whitelist

extension id白名单。

参考:https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/api/_features.md