CEF3和本地程序交互机制
2014年12月02日 20:34:34 _Milo_ 阅读数 11878
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.youkuaiyun.com/oudizuo/article/details/41683153
CEF中一个页面的框架如下图所示:

CefBrowser:一个普通的浏览器页面(HTML)
CefFrame:每一个页面都由至少一个frame组成,最顶层的为mainframe
context:JS执行环境,每个frame都有自己独立的context,CEF中使用V8JavaScriptEngine解析和执行JS代码
后端和前端的通信分为两个部分:
一.C++ call JS:
由框架图可以知道,后端执行JS的实质是:在特定的frame上执行JS代码片段
示例:
-
CefRefPtr<CefBrowser> browser = ...; -
CefRefPtr<CefFrame> frame = browser->GetMainFrame(); -
frame->ExecuteJavaScript("alert('ExecuteJavaScript works!');", -
frame->GetURL(), 0);
可以得知,C++端执行JS的通用流程为:
1.获取页面引用
2.获取目标frame引用
3.在目标frame上调用ExecuteJavaScript执行JS
槽点:函数ExecuteJavaScript的返回值为空,函数中也没有其他形式获取JS执行的返回值。那么JS的返回值如何获取?
二.JS call C++
C++和JS对象的映射关系:

CefValue表示JS环境中的一个对象,其可以表示JS中所有变量,切其自身可以嵌套。特别重要的一点,前端的window对象在后端也是一个CefV8Value,并且可以通过CefV8Context取到它。
JS调用C++的实质是:以CefV8Value的形式包装C++对象,并将其绑定到特定frame的JS执行环境的window对象上,如此JS代码就可以直接对其读写(属性)或者调用(函数)。
A. window binding,将自定义数据绑定到JS context的window对象上
1.在回调CefRenderProcessHandler的OnContextCreated()中注册。注册过程:
1.1获取CefV8Value形式的window对象
1.2构造数据
1.3绑定到window对象上
代码示例:
-
void MyRenderProcessHandler::OnContextCreated( -
CefRefPtr<CefBrowser> browser, -
CefRefPtr<CefFrame> frame, -
CefRefPtr<CefV8Context> context) { -
CefRefPtr<CefV8Value> object = context->GetGlobal();// 获取到window -
CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!"); -
object->SetValue("myval", str, V8_PROPERTY_ATTRIBUTE_NONE); -
}
2.特别注意:在frame reload的时候,需要重新绑定。frame reload其实就是重新创建了context,需要重新执行绑定过程,这很好理解。
3.CefV8Value的setValue方法就是将数据绑定到对象上
B.extensions,将预定义的JS代码注册到context中,并且一旦注册,不可修改。这种方式威力很弱,我想只会在特殊的场景下选它。
在CefRenderProcessHandler的回调OnWebKitInitialized()中执行注册
示例:
-
void MyRenderProcessHandler::OnWebKitInitialized() { -
std::string extensionCode = -
"var test;" -
"if (!test)" -
" test = {};" -
"(function() {" -
" test.myval = 'My Value!';" -
"})();"; -
CefRegisterExtension("v8/test", extensionCode, NULL); -
}
C.数据构造
1. JS基本类型,CEF支持创建基本JS数据类型,比如undefined, null, bool, int, double, date and string。使用静态函数CefV8Value::Create*()
2.JS数组,CefV8Value::CreateArray()
3.JS对象,CefV8Value::CreateObject(NULL)
4.JS function, CefV8Value::CreateFunction();
D.属性读写和函数实现
1.对象读写
创建CefV8Value时,关联一个CefV8Accessor,并实现它的get和set,示例:
//创建时关联CefV8Accessor
CefRefPtr<CefV8Accessor> accessor = …;
CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(accessor);
//实现自己的CefV8Accessor
-
class MyV8Accessor : public CefV8Accessor { -
public: -
MyV8Accessor() {} -
virtual bool Get(const CefString& name, -
const CefRefPtr<CefV8Value> object, -
CefRefPtr<CefV8Value>& retval, -
CefString& exception) OVERRIDE { -
if (name == "myval") { -
// Return the value. -
retval = CefV8Value::CreateString(myval_); -
return true; -
} -
return false; -
} -
virtual bool Set(const CefString& name, -
const CefRefPtr<CefV8Value> object, -
const CefRefPtr<CefV8Value> value, -
CefString& exception) OVERRIDE { -
if (name == "myval") { -
if (value.IsString()) { -
myval_ = value.GetStringValue(); -
} else { -
exception = "Invalid value type"; -
} -
return true; -
} -
return false; -
} -
CefString myval_; -
IMPLEMENT_REFCOUNTING(MyV8Accessor); -
};
2.函数实现
创建函数时,绑定自己实现的CefV8Handler,示例:
CefRefPtr<CefV8Handler> handler = …;
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
//实现自己的CefV8Handler
-
class MyV8Handler : public CefV8Handler { -
public: -
MyV8Handler() {} -
virtual bool Execute(const CefString& name, -
CefRefPtr<CefV8Value> object, -
const CefV8ValueList& arguments, -
CefRefPtr<CefV8Value>& retval, -
CefString& exception) OVERRIDE { -
if (name == "myfunc") { -
retval = CefV8Value::CreateString("My Value!"); -
return true; -
} -
return false; -
} -
IMPLEMENT_REFCOUNTING(MyV8Handler); -
};
本文深入讲解CEF3框架中C++与JavaScript的交互机制,包括C++调用JS、JS调用C++的方法及其实现细节,如ExecuteJavaScript的使用、CefV8Value的数据绑定、属性读写和函数实现等。
3195

被折叠的 条评论
为什么被折叠?



