CEF3和本地程序交互机制

本文深入讲解CEF3框架中C++与JavaScript的交互机制,包括C++调用JS、JS调用C++的方法及其实现细节,如ExecuteJavaScript的使用、CefV8Value的数据绑定、属性读写和函数实现等。

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代码片段

 

示例:

 

 
  1. CefRefPtr<CefBrowser> browser = ...;

  2. CefRefPtr<CefFrame> frame = browser->GetMainFrame();

  3. frame->ExecuteJavaScript("alert('ExecuteJavaScript works!');",

  4. 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对象上

 

代码示例:

 

 
  1. void MyRenderProcessHandler::OnContextCreated(

  2. CefRefPtr<CefBrowser> browser,

  3. CefRefPtr<CefFrame> frame,

  4. CefRefPtr<CefV8Context> context) {

  5. CefRefPtr<CefV8Value> object = context->GetGlobal();// 获取到window

  6. CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!");

  7. object->SetValue("myval", str, V8_PROPERTY_ATTRIBUTE_NONE);

  8. }

 

2.特别注意:在frame reload的时候,需要重新绑定。frame reload其实就是重新创建了context,需要重新执行绑定过程,这很好理解。

3.CefV8Value的setValue方法就是将数据绑定到对象上

 

B.extensions,将预定义的JS代码注册到context中,并且一旦注册,不可修改。这种方式威力很弱,我想只会在特殊的场景下选它。

 

在CefRenderProcessHandler的回调OnWebKitInitialized()中执行注册

示例:

 
  1. void MyRenderProcessHandler::OnWebKitInitialized() {

  2. std::string extensionCode =

  3. "var test;"

  4. "if (!test)"

  5. " test = {};"

  6. "(function() {"

  7. " test.myval = 'My Value!';"

  8. "})();";

  9.  
  10.  
  11. CefRegisterExtension("v8/test", extensionCode, NULL);

  12. }

 

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

 
  1. class MyV8Accessor : public CefV8Accessor {

  2. public:

  3. MyV8Accessor() {}

  4. virtual bool Get(const CefString& name,

  5. const CefRefPtr<CefV8Value> object,

  6. CefRefPtr<CefV8Value>& retval,

  7. CefString& exception) OVERRIDE {

  8. if (name == "myval") {

  9. // Return the value.

  10. retval = CefV8Value::CreateString(myval_);

  11. return true;

  12. }

  13. return false;

  14. }

  15.  
  16. virtual bool Set(const CefString& name,

  17. const CefRefPtr<CefV8Value> object,

  18. const CefRefPtr<CefV8Value> value,

  19. CefString& exception) OVERRIDE {

  20. if (name == "myval") {

  21. if (value.IsString()) {

  22. myval_ = value.GetStringValue();

  23. } else {

  24. exception = "Invalid value type";

  25. }

  26. return true;

  27. }

  28. return false;

  29. }

  30.  
  31. CefString myval_;

  32. IMPLEMENT_REFCOUNTING(MyV8Accessor);

  33. };

 

 

2.函数实现

创建函数时,绑定自己实现的CefV8Handler,示例:

CefRefPtr<CefV8Handler> handler = …;
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);

 

//实现自己的CefV8Handler

 
  1. class MyV8Handler : public CefV8Handler {

  2. public:

  3. MyV8Handler() {}

  4.  
  5. virtual bool Execute(const CefString& name,

  6. CefRefPtr<CefV8Value> object,

  7. const CefV8ValueList& arguments,

  8. CefRefPtr<CefV8Value>& retval,

  9. CefString& exception) OVERRIDE {

  10. if (name == "myfunc") {

  11. retval = CefV8Value::CreateString("My Value!");

  12. return true;

  13. }

  14. return false;

  15. }

  16.  
  17. IMPLEMENT_REFCOUNTING(MyV8Handler);

  18. };

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值