libCEF中C++与JavaScript的交互调

前言

前一篇文章介绍过CEF在WIN32程序中嵌入chrome内核浏览器的例子:http://blog.csdn.net/mfcing/article/details/43973377

这里介绍的是嵌入浏览器后,网页的JS脚本函数与C++代码的交互,这个很多地方都用得到。比如:音乐播放器里网页上的播放,客户端资源中心里的资源下载……


JS调用C++函数

首先需要重写CefRenderProcessHandler的OnContextCreated接口,为什么呢?学习CEF库的使用必须仔细阅读他的头文件里的注视部分:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // Called immediately after the V8 context for a frame has been created. To  
  2. // retrieve the JavaScript 'window' object use the CefV8Context::GetGlobal()  
  3. // method. V8 handles can only be accessed from the thread on which they are  
  4. // created. A task runner for posting tasks on the associated thread can be  
  5. // retrieved via the CefV8Context::GetTaskRunner() method.  
  6. ///  
  7. /*--cef()--*/  
  8. virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,  
  9.                               CefRefPtr<CefFrame> frame,  
  10.                               CefRefPtr<CefV8Context> context) {}  
这个接口实在chrome的V8引擎创建后调用的,在这里我们需要将JS里面调用的函数和C++的执行函数关联起来,这样JS就可以“执行”C++代码了。

我们的函数都是定义在window对象中的(不知道JS中这个是不是叫对象),根据注视我们需要GetGlobal获取这个对象。

我的代码是这样的:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CefRefPtr<CefV8Value> window = context->GetGlobal();  
  2.         CefRefPtr<CefV8Accessor> myV8Acc = new CCefV8Accessor;  
  3.         CefRefPtr<CefV8Value> val = CefV8Value::CreateString(L"Application");  
  4.         CefString cefException;  
  5.         myV8Acc->Set(L"name", window, val, cefException);  
  6.         CefRefPtr<CefV8Value> pObjApp = CefV8Value::CreateObject(myV8Acc);  
  7.         window->SetValue(L"Application", pObjApp, V8_PROPERTY_ATTRIBUTE_NONE);  
  8.   
  9.         CefRefPtr<CefV8Handler> myV8handle = new CCefV8Handler();  
  10.         CefRefPtr<CefV8Value> myFun = CefV8Value::CreateFunction(L"SetAppState", myV8handle);  
  11.         static_cast<CCefV8Handler*>(myV8handle.get())->AddFun(L"SetAppState", &CChromeJsCallback::JsSetAppState);  
  12.         pObjApp->SetValue(L"SetAppState", myFun, V8_PROPERTY_ATTRIBUTE_NONE);  
  13.   
  14.         myFun = CefV8Value::CreateFunction(L"OneClickInstall", myV8handle);  
  15.         static_cast<CCefV8Handler*>(myV8handle.get())->AddFun(L"OneClickInstall", &CChromeJsCallback::JsOneKeyInstall);  
  16.         pObjApp->SetValue(L"OneClickInstall", myFun, V8_PROPERTY_ATTRIBUTE_NONE);  
  17.   
  18.         myFun = CefV8Value::CreateFunction(L"DownLoadFile", myV8handle);  
  19.         static_cast<CCefV8Handler*>(myV8handle.get())->AddFun(L"DownLoadFile", &CChromeJsCallback::JsDownloadFile);  
  20.         pObjApp->SetValue(L"DownLoadFile", myFun, V8_PROPERTY_ATTRIBUTE_NONE);  

所有的JS函数都是在window.Application上的,因此需要在window 对象上面创建Application 对象,CefV8Value::CreateObject用来创建对象。CefV8Value这个类在JS处理中至关重要,要必要好好看看头文件里面的注视,CEF的注视是相当详细的。


创建函数对象,并将JS函数绑定到C++函数指针上面的过程是重点详细介绍下

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CefRefPtr<CefV8Handler> myV8handle = new CCefV8Handler();  
  2.         CefRefPtr<CefV8Value> myFun = CefV8Value::CreateFunction(L"SetAppState", myV8handle);  
  3.         static_cast<CCefV8Handler*>(myV8handle.get())->AddFun(L"SetAppState", &CChromeJsCallback::JsSetAppState);  
  4.         pObjApp->SetValue(L"SetAppState", myFun, V8_PROPERTY_ATTRIBUTE_NONE);  



AddFun是自己添加的一个函数,用来把一个函数和气对应的回调地址存储到这个V8对象中,因此用了一个成员变量typedef map<CefString, JS_CALLBACK_FUN> FunctionMap,调用函数时V8引擎有一个接口Execute,在这里我们调用函数的名称到map中去查找,找到了其对应的回调地址调用函数,这就是JS调用C++的过程了。


最上面那段代码中,我们又添加了三个函数 SetAppState、OneClickInstall、DownLoadFile到window.application对象上面。


C++代码中,这三个函数是这样写的:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //JS函数,在其他进程中调用  
  2.     static bool JsSetAppState(const CefV8ValueList& argList, CefRefPtr<CefV8Value>& retValue);  
  3.     static bool JsOneKeyInstall(const CefV8ValueList& argList, CefRefPtr<CefV8Value>& retValue);  
  4.     static bool JsDownloadFile(const CefV8ValueList& argList, CefRefPtr<CefV8Value>& retValue);  

vCefV8ValueList是一个参数列表,看它的定义typedef std::vector<CefRefPtr<CefV8Value> > CefV8ValueList,retValue当然就是函数的返回值了,有的JS需要根据返回值做相应的处理的。

这里要注意:CEF可以使用单进程和多进程模式,我程序里使用的是多进程模式,因此V8引擎的执行是在渲染引擎里的,不要尝试在这里直接去对界面进行处理。界面进程和渲染进程是分开的,数据的话用共享内存来做,界面更新发消息来做。


C++调用JS函数

C++调用JS函数相对简单多了,因为CEF有接口可以直接使用CefFrame::ExecuteJavaScript,看看注释:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // Execute a string of JavaScript code in this frame. The |script_url|  
  2. // parameter is the URL where the script in question can be found, if any.  
  3. // The renderer may request this URL to show the developer the source of the  
  4. // error.  The |start_line| parameter is the base line number to use for error  
  5. // reporting.  
  6. ///  
  7. /*--cef(optional_param=script_url)--*/  
  8. virtual void ExecuteJavaScript(const CefString& code,  
  9.                                const CefString& script_url,  
  10.                                int start_line) =0;  

首先需要获取到我们的浏览器里的主框架对象,code是JS函数和传入参数的字符串,URL可以直接忽略。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CChromeBrowserUI::ExecuteJavascript( const wstring& strCode )  
  2. {  
  3.     if ( m_pWebBrowser.get() )  
  4.     {  
  5.         CefRefPtr<CefFrame> frame = m_pWebBrowser->GetMainFrame();  
  6.         if ( frame.get() )  
  7.         {  
  8.             CefString strCode(strCode.c_str()), strUrl(L"");  
  9.             frame->ExecuteJavaScript(strCode, strUrl, 0);  
  10.         }  
  11.     }  
  12. }  
注意:函数名和参数名需要用单引号分隔。

我的字符串格式化部分:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CString strJsCode;  
  2.     strJsCode.Format(L"setInstallStatus('%s','%s','%d');", lpData->strId.c_str(), strStatus, nPercent);  

这样,C++就可以调用JS的函数并传入对应的参数了。

总结

要想使用CEF,最好还是仔细阅读头文件里面的注释,很详细。

运行程序


版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值