不同编程语言的开发效率是不一样的,比如c++可以实现一些很底层的功能,但是开发速度比较慢,对开发者的要求也很高。而javascript开发速度很快,编程的抽象层次很高,无法调用一些系统底层的api。于是我们想到可以把c++与javascript结合起来,c++给javascript提供一些底层的api接口,javascript调用c++的接口并专注于业务开发,这样岂不两全其美。
事实上真有这样做的,比如Chromium浏览器,浏览器本身是用c++编写的,提供了很多extension api,然后我们可以用javascript调用这些extension api制作一些extension扩展程序,为浏览器提供更多的功能。
extension api
Chrome浏览器提供了很多extension api,打开开发者工具,在Console里面输入window.chrome,如下图所示:

我们在Console输入以下javascript代码:
chrome.tabs.create(
{"url":"https://www.baidu.com","selected":true},
function(tab){
console.log(tab.id);
}
);
浏览器会在一个新标签页打开https://www.baidu.com,并调用我们传给chrome.tabs.create的会调函数,如下图所示:

新增extension api
虽然Chromium已经提供了很多extension api,有时候我们会出于各种目的,会想增加自己的extension api。我就添加一个gclxry的api,来描述如何操作。
增加api feature定义
我们在chrome\common\extensions\api_api_features.json或者extensions\common\api_api_features.json文件里面增加gclxry的api feature定义。这两个目录下面的_api_features.json的差异是:chrome目录下的api与浏览器的业务更加紧密而extensions目录下的api则是更加独立的javascript api。
我们在chrome\common\extensions\api_api_features.json里面增加以下内容:
"gclxry": {
"matches": ["<all_urls>"],
"channel": "stable",
"extension_types": "all",
"contexts": "all"
},
gclxry就是我们api的名字,这个对象有几个字段,具体可以参考我之前写的博客http://blog.gclxry.com/chrome-extension-features:
- matches,符合了调用该api接口网页的url。我们设置为””表示所有的网页都可以调用该api。
- channel,表示浏览器的channle。
- extension_types,表示所有类型的extension都可以调用该api。
- contexts,表示所有的javascript context都可以调用该api。
从gcxlry api feature定义可以看出来,我们把这个api的权限放的很开,这样是为了方便测试。实际开发中,我们不应该开放这么大的权限。
另外Chromium提供的api权限,更多的是定义到_permission_features.json文件里面。我们把权限都定义到_api_features.json文件里面,也是为了简单。
增加api接口定义
api接口的定义就是定义api的参数和返回值。这里有两种定义格式:
- json格式,功能更强大,但是语法比较繁琐,不直观。
- idl格式,语法更易懂,推荐使用这种。
可惜json和idl格式Chromium都没有提供完整的文档描述如何使用。不过我们看看chrome\common\extensions\api和extensions\common\api里面其他api接口的json和idl文件定义文件,大概学学就知道了。
我们在chrome\common\extensions\api目录里添加一个gclxry.idl文件,其内容如下:
namespace gclxry {
callback Callback = void (DOMString result);
interface Functions {
static void hello(DOMString name, optional Callback callback);
};
};
这样我们就定义了一个chrome.gclxry的js对象。它有一个函数hello,接受接受一个字符串的参数并又一个可选的回调函数参数。
然后把gclxry.idl文件加入Build.gn工程配置文件里。
添加api的c++实现代码
我们在chrome\browser\extensions\api\gclxry目录里添加代码文件gclxry_api.h,gclxry_api.cc,并加入到Build.gn工程配置文件里。
gclxry_api.h文件的内容如下:
#ifndef CHROME_BROWSER_EXTENSIONS_API_BROWSER_GCLXRY_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_BROWSER_GCLXRY_API_H_
#include "chrome/browser/extensions/chrome_extension_function.h"
namespace extensions {
namespace api {
class GclxryHelloFunction : public ChromeUIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("gclxry.hello", GCLXRY_HELLO)
protected:
~GclxryHelloFunction() override;
ResponseAction Run() override;
};
} // namespace api
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_BROWSER_GCLXRY_API_H_
gclxry_api.cc文件的内容如下:
#include "chrome/browser/extensions/api/gclxry/gclxry_api.h"
#include "chrome/common/extensions/api/gclxry.h"
namespace extensions {
namespace api {
GclxryHelloFunction::~GclxryHelloFunction() {}
ExtensionFunction::ResponseAction GclxryHelloFunction::Run() {
std::unique_ptr<gclxry::Hello::Params> params(
gclxry::Hello::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
std::string error("hello error message");
std::string data = std::string("hello ") + params->name;
std::unique_ptr<base::ListValue> result(gclxry::Hello::Results::Create(data));
if (!result)
return RespondNow(Error(error));
return RespondNow(ArgumentList(std::move(result)));
}
} // namespace api
} // namespace extensions
GclxryHelloFunction 类就是chrome.gclxry.hello函数的实现。
此外还要在extension_function_histogram_value.h里面添加一个GCLXRY_HELLO。
测试新增的api
我们打开个设置页面,这个设置页面的javascript context类型是webui。打开console,输入:
我们打开个设置页面,这个设置页面的javascript context类型是webui。打开console,输入:
chrome.gclxry.hello(
'world',
function say_hello(data){
console.log(data);
}
);
效果如下图:

然后我们打开https://www.baidu.com/,打开开发者工具,在console里面chrome却没有gclxry对象,原因是extension api默认只能在extension_service_worker、blessed_extension、unblessed_extension、content_script、webui这几种javascript context里面存在。而一般的网页的javascript context是web_page类型。因此我们需要在Dispatcher::UpdateBindingsForContext里面添加如下两行代码:

参考:http://dev.chromium.org/developers/design-documents/extensions/proposed-changes/creating-new-apis