CEF中JavaScript与C++交互
2016-09-20 18:11
2231 查看
在CEF里,JS和Native(C/C++)代码可以很方便的交互,讲解得很清楚。我照着它实现了一个简单的交互示例。
在贴代码之前,先来看看Browser进程和Render进程是怎么回事儿,有什么不同。
?
它分析了命令行参数,提取”type”参数,如果为空,说明是Browser进程,返回-1,这样一路回溯到wWinMain方法里,然后开始创建Browser进程相关的内容。
如果”type”参数不为空,做一些判断,最后调用了content::ContentMain方法,直到这个方法结束,子进程随之结束。
content::ContentMain方法再追溯下去,就到了chromium的代码里了,在chromium/src/content/app/content_main.cc文件中。具体我们不分析了,感兴趣的可以去看看。
分析了CefExecuteProcess方法我们知道,Browser进程在cefsimple_win.cc内调用了CefExecuteProcess之后做了进一步的配置,这个是在simple_app.cc内完成的,具体就是SimpleApp::OnContextInitialized()这个方法,代码如下:
?
可以看到,这里创建SimpleHandler,并传递给CefBrowserHost::CreateBrowser去使用。
现在我们清楚了,Browser进程,需要CefApp(SimpleApp实现了这个接口)和CefClient(SimpleHandler实现了这个接口)。而Renderer进程只要CefApp。
另外,CEF还定义了CefBrowserProcessHandler和CefRenderProcessHandler两个接口,分别来处理Browser进程和Render进程的个性化的通知。因此,Browser进程的App一般还需要实现CefBrowserProcessHandler接口,Renderer进程的App一般还需要实现CefRenderProcessHandler接口。这里https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage有详细说明。
像cefsimple这个示例中的SimpeApp,没有实现CefRenderProcessHandler接口,没有针对Renderer进程做特别处理,所以当它作为Render进程时,会缺失一部分功能。比如JS与Native代码交互,这正是我们想要的。
如果要实现JS与Native代码交互,最好分开实现Browser进程需要的CefApp和Render进程需要的CefApp。像下面这样:
?
当我们实现了CefRenderProcessHandler接口,就可以在其OnContextCreated()方法中获取到CefFrame对应的window对象,在它上面绑定一些JS函数或对象,然后JS代码里就可以通过window对象访问,如果是函数,就会调用到我们实现的CefV8Handler接口的Execute方法。
另外一种实现JS与Native交互的方式,是在实现C
17364
efRenderProcessHandler的OnWebKitInitialized()方法时导出JS扩展,具体参考https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md,有详细说明。
JS和Native代码的交互发生在Render进程,App需要继承CefRenderProcessHandler来整合JS相关功能。因此在应用在启动时做了进程类型判断,根据不同的进程类型创建不同的CefApp。
这个示例演示了三种JS交互方式(参见https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md):
- 在native代码中通过CefFrame::ExecuteJavaScript()来执行JavaScript代码
- 将函数或对象绑定到CefFrame对应的window对象上,JS代码通过window对象访问native代码导出的函数或对象
- 使用CefRegisterExtension()注册JS扩展,JS直接访问注册到JS Context中的对象
这个项目参考了cefsimple、cefclient,还有https://github.com/acristoffers/CEF3SimpleSample,最终它比cefsimple复杂一点,比cefclient简单很多。
好啦,背景差不多,上源码。
cef_js_integration.cpp:
?
可以看到,_tWinMain方法中解析了命令行参数,根据进程类型创建了不同的CefApp。这是它与cefsimple的区别。
ClientAppBrowser类与cefsimple示例中的SimpleApp基本一致,略过。
ClientAppRender类在ClientAppRender.h和ClientAppRender.cpp中实现。先是ClientAppRender.h:
?
ClientAppRender聚合了ClientV8Handler类的实例,回头再说。先来看ClientAppRender的OnContextCreated和OnWebKitInitialized,它们是实现JS与Native交互的关键。代码如下:
?
OnContextCreated给window对象绑定了一个NativeLogin函数,这个函数将由ClientV8Handler类来处理,当HTML中的JS代码调用window.NativeLogin时,ClientV8Handler的Execute方法会被调用。
OnWebKitInitialized注册了一个名为app的JS扩展,在这个扩展里为app定义了GetId方法,app.GetId内部调用了native版本的GetId()。HTML中的JS代码可能如下:
?
当浏览器执行上面的代码时,ClientV8Handler的Execute方法会被调用。
好啦,现在来看ClientV8Handler的实现(V8Handler.cpp):
?
Execute在处理GetId方法时,还使用CefFrame::ExecuteJavaScript演示了如何在native代码中执行JS代码。
最后,来看一下html代码:
<script type="text/javascript"> function Login(){ window.NativeLogin(document.getElementById("userName").value, document.getElementById("password").value); } function GetId(){ alert("get id from native by extensions: " + app.GetId()); } </script>
?
通过下面的命令可以测试:
?
在CEF里,JS和Native(C/C++)代码可以很方便的交互,讲解得很清楚。我照着它实现了一个简单的交互示例。
在贴代码之前,先来看看Browser进程和Render进程是怎么回事儿,有什么不同。
Browser与Render进程
从cefsimple开始吧,cefsimple_win.cc中的wWinMain函数中调用了CefExecuteProcess()方法来检测是否要启动其它的子进程。此处的CefExecuteProcess是在libcef_dll_wrapper.cc中的,它内部又调用了cef_execute_process方法(libcef_dll.cc),cef_execute_process又调用了libcef/browser/context.cc文件内实现的CefExecuteProcess方法。这个方法代码如下:?
如果”type”参数不为空,做一些判断,最后调用了content::ContentMain方法,直到这个方法结束,子进程随之结束。
content::ContentMain方法再追溯下去,就到了chromium的代码里了,在chromium/src/content/app/content_main.cc文件中。具体我们不分析了,感兴趣的可以去看看。
分析了CefExecuteProcess方法我们知道,Browser进程在cefsimple_win.cc内调用了CefExecuteProcess之后做了进一步的配置,这个是在simple_app.cc内完成的,具体就是SimpleApp::OnContextInitialized()这个方法,代码如下:
?
现在我们清楚了,Browser进程,需要CefApp(SimpleApp实现了这个接口)和CefClient(SimpleHandler实现了这个接口)。而Renderer进程只要CefApp。
另外,CEF还定义了CefBrowserProcessHandler和CefRenderProcessHandler两个接口,分别来处理Browser进程和Render进程的个性化的通知。因此,Browser进程的App一般还需要实现CefBrowserProcessHandler接口,Renderer进程的App一般还需要实现CefRenderProcessHandler接口。这里https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage有详细说明。
像cefsimple这个示例中的SimpeApp,没有实现CefRenderProcessHandler接口,没有针对Renderer进程做特别处理,所以当它作为Render进程时,会缺失一部分功能。比如JS与Native代码交互,这正是我们想要的。
如果要实现JS与Native代码交互,最好分开实现Browser进程需要的CefApp和Render进程需要的CefApp。像下面这样:
?
另外一种实现JS与Native交互的方式,是在实现C
17364
efRenderProcessHandler的OnWebKitInitialized()方法时导出JS扩展,具体参考https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md,有详细说明。
cef_js_integration项目
cef_js_integration是非常简单的示例,用来演示JS与Native的交互。它在一个项目内实现了ClientAppBrowser、ClientAppRenderer、ClientAppOther三种CefApp,分别对应Browser、Render及其它类别的三种进程。JS和Native代码的交互发生在Render进程,App需要继承CefRenderProcessHandler来整合JS相关功能。因此在应用在启动时做了进程类型判断,根据不同的进程类型创建不同的CefApp。
这个示例演示了三种JS交互方式(参见https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md):
- 在native代码中通过CefFrame::ExecuteJavaScript()来执行JavaScript代码
- 将函数或对象绑定到CefFrame对应的window对象上,JS代码通过window对象访问native代码导出的函数或对象
- 使用CefRegisterExtension()注册JS扩展,JS直接访问注册到JS Context中的对象
这个项目参考了cefsimple、cefclient,还有https://github.com/acristoffers/CEF3SimpleSample,最终它比cefsimple复杂一点,比cefclient简单很多。
好啦,背景差不多,上源码。
cef_js_integration.cpp:
?
ClientAppBrowser类与cefsimple示例中的SimpleApp基本一致,略过。
ClientAppRender类在ClientAppRender.h和ClientAppRender.cpp中实现。先是ClientAppRender.h:
?
?
OnWebKitInitialized注册了一个名为app的JS扩展,在这个扩展里为app定义了GetId方法,app.GetId内部调用了native版本的GetId()。HTML中的JS代码可能如下:
?
好啦,现在来看ClientV8Handler的实现(V8Handler.cpp):
?
最后,来看一下html代码:
<script type="text/javascript"> function Login(){ window.NativeLogin(document.getElementById("userName").value, document.getElementById("password").value); } function GetId(){ alert("get id from native by extensions: " + app.GetId()); } </script>
Call into native by Window bindings:
?Call into native by js extensions:
通过下面的命令可以测试:
?
相关文章推荐
- CEF中JavaScript与C++交互
- CEF中JavaScript与C++交互
- CEF中JavaScript与C++交互
- Duilib嵌入CEF以及JavaScript与C++交互
- CEF3开发者系列之JS与C++交互之一
- CEF3开发者系列之JS与C++交互之二
- Cocos2d-x的SprideMonkey的JavaScript与C++的交互(四) - 灰常好用的一个函数eval
- VC与JavaScript交互(三) ———— JS调用C++
- 利用MFC实现浏览器的定制与扩展(JavaScript与C++交互)
- MFC使用CEF并实现js与C++交互功能,解决Render进程中OnContextCreated绑定与OnWebKitInitialized的js扩展无法回调问题
- 利用MFC实现浏览器的定制与扩展(JavaScript与C++交互)
- IWebbrowser2中C++与JavaScript的交互调用
- VC与JavaScript交互(三) ———— JS调用C++
- 交互修改Cocos2d-x的SprideMonkey的JavaScript与C++的交互 - 单个全局变量操作
- Cocos2d-x的SprideMonkey的JavaScript与C++的交互
- Qt webKit--实现本地QObject(c++)和JavaScript交互
- libCEF中C++与JavaScript的交互调用【编程语言】
- Cocos2d-x的SpiderMonkey的JavaScript与C++的交互(二) - 单个全局变量操作
- Cocos2d-x的SpiderMonkey的JavaScript与C++的交互(一) - 函数操作
- Cocos2d-x的SprideMonkey的JavaScript与C++的交互(二) - 单个全局变量操作