这个是去年做过的一个项目,主要是通过js,html做前端,然后c++对象再后面提供服务。
比较简单的一个场景是,你可以想象为什么你在浏览器内可以写windows,document这些对象来操作一些方法和属性,本质上这些对象都是c++实现的,也可以称为预定义对象,那么我们如何将一些自定义的方法或者对象暴露给js呢?
v8中c++暴露给js的方式大体上有两种,extention 和mapping机制。
前者往往用于将一些API 暴露出去,比较全局函数,比如printlog,getpath这些全局的函数。
mapping机制,比较容易将对象暴露出去。
那么先讲讲extention机制。
首先v8中对象的执行本质上需要一个context对象,可以理解为上下文,通常浏览器的一个frame就是一个context。
那么我们假设想让某个上下文中有一个我们自定义的函数比如叫做getpath。
1。 我们需要创建一个context,这儿假定它叫做globalctx。
const char* appExtension = "Extensions/Application";
Application::Application(void) :
v8::Extension( appExtension,
"native function GetPath();"
"native function include();"
)
{
FunctionTemplate::New(Include));
}
2. 我们需要在这个globalctx中,注册extention,这个注册过程就是解决了在这个context中注入了一些我们定义的对象和方法。
void GlobalContext::Initialize( ExtensionList* extensions )
{
m_objectGlobal = v8::ObjectTemplate::New();
// register extensions in global javascript context
std::vector vecExtensions;
scoped_ptr extensionConfig;
if ( extensions && extensions->size() )
{
for ( ExtensionList::iterator iter = extensions->begin(); iter != extensions->end(); iter ++ )
{
vecExtensions.push_back( (*iter)->name() );
v8::RegisterExtension( *iter );
}
extensionConfig.reset( new v8::ExtensionConfiguration( (int)vecExtensions.size(), &vecExtensions[0] ) );
}
m_context = v8::Context::New( extensionConfig.get(), m_objectGlobal );
}
通过这个方式,将extention注入这个context,这样getpath这个方法将可以在这个context的js代码中可以访问。 再深一步说为什么,就需要看v8的source了。
我们再来看第二个问题,即如何让一个c++对象再js中可以访问,刚才的说明你会发现光通过extention模式,它只能export API 而不能暴露对象,而且API往往很多时候是无状态的,即用了就用了;但是实际上我们可能会存在一些有状态的对象,比如user对象,它是由名称和昵称的,另外或许它运行过程中间昵称会变化。
简单来说,从实际使用角度出发,我们需要在js有能力可以如下:
var obj = xxxx; // obj hold a c++ object
var dispname = obj.getdispname() // we can access method of obj
大致就这么个意思。。。。,而这个靠extention就不行了。
我们看看v8提供的mapping机制。。。
这儿假设extention提供了一个方法叫做GetServiceMgr,它返回一个rootobj,你明白就行。
然后这个rootobj上有很多方法。。。
贴一些代码。。。
v8::Handle IMAPIExtension::GetServiceMgr(const v8::Arguments& args)
{
using namespace ImAPI;
using namespace v8;
HandleScope handleScope;
v8::Handle context = v8::Context::GetCurrent();
if(context.IsEmpty())
{
return False();
}
v8::Context::Scope contextScope(context);
if(!m_serviceManager)
{
return v8::Null();
}
return handleScope.Close(ImMapping::CppDataToJsData(m_serviceManager));
}
v8::Handle CppDataToJsData(ImAPI::IServiceManager* pServiceMgr)
{
if(!pServiceMgr)
{
return Null();
}
v8::HandleScope handleScope;
v8::Handle context = v8::Context::GetCurrent();
if(context.IsEmpty())
{
return False();
}
Context::Scope contextScope(context);
Handle retObjectValue = MapCppObjectToJs(pServiceMgr);
if(retObjectValue.IsEmpty())
{
return False();
}
if(!FillFunction2Object("GetCurrentUserService",retObjectValue,&InvokerProc::HandleProc))
{
return False();
}
......... 注册其他对象,这个就是mapping.....
这样以后,我们就可以写,如下js 。。。。
var servicemgr = GetServiceMgr();
var cus = servicemgr.GetCurrentUserService();
到了这儿已经简单的介绍了v8的c++对象扩展机制,但是还是有一些问题,没有得到很好的回到,比如这个暴露出去的对象它的生命周期如何管理?
这个是我的demo没有触及到的,demo只是假设了暴露出去的是一些全局单件对象。
其实结合qtwebkit bridge的做法,我这儿的建议是,最好还是c++方面管理这些对象的生命周期;
而不是依赖于v8的gc。 (貌似v8的gc在发生的时候可以注册回调)
然后通过显式的调用来放弃对象生命周期,比如js端不用了,就call一个uninit之类的。
下面是demo的附件。
|
文件: | Evolution.rar |
大小: | 238KB |
下载: | 下载 |
|
阅读(2241) | 评论(0) | 转发(0) |