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:
- _api_features。对应的是代码中的_api_features.json文件的内容,指定了api可用性的要求。如果extension不满足要求,那么extension中的代码不能调用该api。
- _permission_features。对应的是代码中的_permission_features.json文件的内容,指定了permission可用性的要求。如果extension不满足要求,那么不会获取到该permission,并且在安装该extension的时候会有警告。
- _manifest_features。对应的是代码中的_manifest_features.json文件的内容,指定了manifest可用性的要求。如果extension不满足要求,那么extension会加载失败。
- _behavior_features。对于的是代码中的_behavior_features.json文件中的内容。这个很少使用。
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有以下几种类型:
- blessed_extension,指的是运行在extension进程里面的javascript context。这通常是一种最安全的javascript context。通常只有顶层的extension框架(具有chrome-extension://),extension popup,app窗口的页面,才是blessed extension contexts。extension frame运行在一个网页上面也认为是blessed extension contexts。
- blessed_web_page,指的是javascript context运行在hosted app里面。与blessed_extension一样也是与其他进程隔离的。
- content_script,指的是extension context srcipt,当它的进程与其他网页共享,会认为是非常不安全的context。很少的feature会暴露给这个context。
- extension_service_worker,指的是extension‘s service worker的javascript context。很少用。
- web_page,指的是运行在网页上的javascript context,与extension完全隔离,这是最不安全的context。必须提供matches属性。
- webui,指的是运行在webui里面的javascript context。
- unblessed_extension,指的是运行在嵌入到外部页面的extension frame的javascript 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
让子类不继承父类的属性。
feature支持的平台,有以下值:chromeos、mac、linux、win。
whitelist
extension id白名单。
参考:https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/api/_features.md