转载:http://blog.csdn.net/foruok/article/details/50573612

转载:http://blog.csdn.net/foruok/article/details/50584985

转载:http://blog.csdn.net/mfcing/article/details/44539035

转载:https://github.com/fanfeilong/cefutil/blob/master/doc/CEF_JavaScript_Cpp.md

转载:https://blog.csdn.net/aseseven/article/details/79482515(CEF3加载本地HTML文件时中文路径乱码的问题解决办法)

转载:https://blog.csdn.net/u012778714/article/category/7003599

JS与Native代码交互,是在Render进程中,所以我们要实现CefRenderProcessHandler接口

一、JS 调用 C++

  • JavaScript注册函数给Render进程,Render进程保存该JavaScript函数
  • Render进程发消息通知Browser进程
  • Browser进程处理后,回发消息给Render进程
  • Render进程调用之前保存的JavaScript函数

1.带参数没有返回值

自己的APP类要继承于CefRenderProcessHandler

 #ifndef _CEFBROWSERAPP_H_
#define _CEFBROWSERAPP_H_
#include "include/cef_app.h"
#include "CEFV8HandlerEx.h" class CCefBrowserApp
: public CefApp
, public CefBrowserProcessHandler
, public CefRenderProcessHandler
{
public:
CCefBrowserApp(); virtual ~CCefBrowserApp(); public:
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()OVERRIDE { return this; }; public:
// CefBrowserProcessHandler methods:
virtual void OnContextInitialized(); //CefRenderProcessHandler methods
virtual void OnWebKitInitialized(); CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE{ return this; } virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); virtual void OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); protected: CefRefPtr<CCEFV8HandlerEx> m_v8Handler; IMPLEMENT_REFCOUNTING(CCefBrowserApp);
};
#endif //_CEFBROWSERAPP_H_

.cpp

 #include "CefBrowserApp.h"
#include "stdafx.h" CCefBrowserApp::CCefBrowserApp()
:m_v8Handler(new CCEFV8HandlerEx)
{
} CCefBrowserApp::~CCefBrowserApp()
{
} void CCefBrowserApp::OnContextInitialized()
{
// do nothing here, because we will create browser in my own dialog
} void CCefBrowserApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
// Retrieve the context's window object.
CefRefPtr<CefV8Value> object = context->GetGlobal(); // Create the "NativeLogin" function.
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("NativeLogin", m_v8Handler); // Add the "NativeLogin" function to the "window" object.
object->SetValue("NativeLogin", func, V8_PROPERTY_ATTRIBUTE_NONE);
} void CCefBrowserApp::OnWebKitInitialized()
{
std::string app_code =
"var app;"
"if (!app)"
" app = {};"
"(function() {"
" app.GetId = function() {"
" native function GetId();"
" return GetId();"
" };"
"})();"; // Registered Javascript Function, which will be called by Cpp
" app.registerJavascriptFunction = function(name,callback) {"
" native function registerJavascriptFunction();"
" return registerJavascriptFunction(name,callback);"
" };" "})();"; CefRegisterExtension("v8/app", app_code, m_v8Handler);//第一个参数不能为空,否则报错,这个名字可以自定义
} 注:CefRegisterExtension的注释
// Example JavaScript extension code:
// <pre>
// // create the 'example' global object if it doesn't already exist.
// if (!example)
// example = {};
// // create the 'example.test' global object if it doesn't already exist.
// if (!example.test)
// example.test = {};
// (function() {
// // Define the function 'example.test.myfunction'.
// example.test.myfunction = function() {
// // Call CefV8Handler::Execute() with the function name 'MyFunction'
// // and no arguments.
// native function MyFunction();
// return MyFunction();
// };
// // Define the getter function for parameter 'example.test.myparam'.
// example.test.__defineGetter__('myparam', function() {
// // Call CefV8Handler::Execute() with the function name 'GetMyParam'
// // and no arguments.
// native function GetMyParam();
// return GetMyParam();
// });
// // Define the setter function for parameter 'example.test.myparam'.
// example.test.__defineSetter__('myparam', function(b) {
// // Call CefV8Handler::Execute() with the function name 'SetMyParam'
// // and a single argument.
// native function SetMyParam();
// if(b) SetMyParam(b);
// });
//
// // Extension definitions can also contain normal JavaScript variables
// // and functions.
// var myint = 0;
// example.test.increment = function() {
// myint += 1;
// return myint;
// };
// })();
// </pre>
// Example usage in the page:
// <pre>
// // Call the function.
// example.test.myfunction();
// // Set the parameter.
// example.test.myparam = value;
// // Get the parameter.
// value = example.test.myparam;
// // Call another function.
// example.test.increment();
// </pre>
///
 void CCefBrowserApp::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
m_v8Handler = nullptr;
}

OnContextCreated给window对象绑定了一个NativeLogin函数,这个函数将由ClientV8Handler类来处理,当HTML中的JS代码调用window.NativeLogin时,ClientV8Handler的Execute方法会被调用。

OnWebKitInitialized注册了一个名为app的JS扩展,在这个扩展里为app定义了GetId方法,app.GetId内部调用了native版本的GetId()。HTML中的JS代码可能如下:

alert(app.GetId());

当浏览器执行上面的代码时,CCEFV8HandlerEx的Execute方法会被调用,现在来看CCEFV8HandlerEx的实现

.h

 #ifndef _CEFV8HANDLEREX_H_
#define _CEFV8HANDLEREX_H_ #include "include/cef_v8.h" class CCEFV8HandlerEx : public CefV8Handler {
public:
CCEFV8HandlerEx(); ~CCEFV8HandlerEx();
public:
virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) override;
private:
// Map of message callbacks.
typedef std::map<std::pair<std::string, int>, std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >CallbackMap;
CallbackMap callback_map_; protected:
IMPLEMENT_REFCOUNTING(CCEFV8HandlerEx);
};
#endif//_CEFV8HANDLEREX_H_

.cpp

 #include "CEFV8HandlerEx.h"
#include "stdafx.h"
#include <strsafe.h> CCEFV8HandlerEx::CCEFV8HandlerEx()
{ } CCEFV8HandlerEx::~CCEFV8HandlerEx()
{
// Remove any JavaScript callbacks registered for the context that has been released.
if (!callback_map_.empty()) {
CallbackMap::iterator it = callback_map_.begin();
for (; it != callback_map_.end();) {
if (it->second.first->IsSame(it->second.first))
callback_map_.erase(it++);
else
++it;
}
}
} bool CCEFV8HandlerEx::Execute(const CefString& name /*JavaScript调用的C++方法名字*/, CefRefPtr<CefV8Value> object /*JavaScript调用者对象*/, const CefV8ValueList& arguments /*JavaScript传递的参数*/, CefRefPtr<CefV8Value>& retval /*返回给JS的值设置给这个对象*/, CefString& exception/*通知异常信息给JavaScript*/)
{
if (name == "NativeLogin")
{//Window Binding
if (arguments.size() == )
{
CefString strUser = arguments.at()->GetStringValue();
CefString strPassword = arguments.at()->GetStringValue(); //TODO: doSomething() in native way CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("login_msg"); // Retrieve the argument list object.
CefRefPtr<CefListValue> args = msg->GetArgumentList(); // Populate the argument values.
args->SetSize();
args->SetString(, strUser);
args->SetString(, strPassword); // Send the process message to the browser process.
CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg); retval = CefV8Value::CreateInt();//函数的返回值 我们可以拿这个返回值做判断或者其他操作
//var result = window.NativeLogin(document.getElementById("userName").value, document.getElementById("password").value);
//document.getElementById("text").innerHTML = result
         }
else
{
retval = CefV8Value::CreateInt();
}
return true;
}
else if (name == "GetId")
{//JS Extensions
if (arguments.size() == )
{
// execute javascript
// just for test
CefRefPtr<CefFrame> frame = CefV8Context::GetCurrentContext()->GetBrowser()->GetMainFrame();
frame->ExecuteJavaScript("alert('Hello, I came from native world.')", frame->GetURL(), ); // return to JS
retval = CefV8Value::CreateString("");
return true;
}
}
// Function does not exist.
return false;
}

在Browser进程中接受Render进程发过来的消息

重写 virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process,CefRefPtr<CefProcessMessage> message);这个虚函数

我把C++函数都写在了窗口类中,所以我对CCefBrowserEventHandler做了修改,把窗口指针传到Browser中,方便调用

.h

 #ifndef _CEFBROWSEREVENTHANDLER_H_
#define _CEFBROWSEREVENTHANDLER_H_
#include "include/cef_client.h"
#include "include/base/cef_lock.h" //线程安全 class CMainFrameWnd; class CCefBrowserEventHandler
: public CefClient
, public CefDisplayHandler // 显示变化事件
, public CefLoadHandler // 加载错误事件
, public CefLifeSpanHandler // 声明周期事件
//, public CefContextMenuHandler // 上下文菜单事件
//, public CefDialogHandler // 对话框事件
//, public CefDownloadHandler // 下载事件
//, public CefDragHandler // 拖拽事件
//, public CefFindHandler // 查找事件
//, public ...
{
public:
CCefBrowserEventHandler(CMainFrameWnd* pMainFrame); virtual ~CCefBrowserEventHandler(); public:
// CefClient 事件处理器,如果没有对应处理器则默认使用内部处理器
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE;
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE;
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE; public:
// display handler method
virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE; public:
// load handler method
virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) OVERRIDE; public:
// display handler meethod
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE; virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message); bool IsClosing() const { return m_bIsClosing; } CefRefPtr<CefBrowser> GetBrowser(){return m_Browser;} protected: CefRefPtr<CefBrowser> m_Browser; bool m_bIsClosing; CMainFrameWnd* m_pMainWnd; IMPLEMENT_REFCOUNTING(CCefBrowserEventHandler);
//由于CEF采用多线程架构,有必要使用锁和闭包来保证在多不同线程安全的传递数据。IMPLEMENT_LOCKING定义提供了Lock()和Unlock()方法以及AutoLock对象来保证不同代码块同步访问
IMPLEMENT_LOCKING(CCefBrowserEventHandler);//必须包含#include "include/base/cef_lock.h"
}; #endif//_CEFBROWSEREVENTHANDLER_H_

.cpp

 #include "CefBrowserEventHandler.h"
#include "stdafx.h"
#include <sstream>
#include <string>
#include "include/cef_app.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "MainFrameWnd.h" CCefBrowserEventHandler::CCefBrowserEventHandler(CMainFrameWnd* pMainFrame)
:m_bIsClosing(false)
,m_pMainWnd(pMainFrame)
{ } CCefBrowserEventHandler::~CCefBrowserEventHandler()
{ } CefRefPtr<CefDisplayHandler> CCefBrowserEventHandler::GetDisplayHandler()
{
return this;
} CefRefPtr<CefLifeSpanHandler> CCefBrowserEventHandler::GetLifeSpanHandler()
{
return this;
} CefRefPtr<CefLoadHandler> CCefBrowserEventHandler::GetLoadHandler()
{
return this;
} void CCefBrowserEventHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title)
{ } void CCefBrowserEventHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode,
const CefString& errorText, const CefString& failedUrl)
{
CEF_REQUIRE_UI_THREAD();
if (ERR_ABORTED == errorCode)
return ; std::stringstream ss;
ss << "<html><body bgcolor=\"white\">"
"<h2>Failed to load URL " << std::string(failedUrl) <<
" with error " << std::string(errorText) << " (" << errorCode <<
").</h2></body></html>";
frame->LoadString(ss.str(), failedUrl);
} void CCefBrowserEventHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_UI_THREAD(); //base::AutoLock lock_scope(lock_); AutoLock lock_scope(this); m_Browser = browser; } bool CCefBrowserEventHandler::DoClose(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_UI_THREAD(); //base::AutoLock lock_scope(lock_);
AutoLock lock_scope(this); if(m_Browser)
{
// Set a flag to indicate that the window close should be allowed.
m_bIsClosing = true;
} return false;
} void CCefBrowserEventHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_UI_THREAD(); //base::AutoLock lock_scope(lock_);
AutoLock lock_scope(this); if(m_Browser->IsSame(browser))
m_Browser = NULL;
} bool CCefBrowserEventHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
{
const std::string& messageName = message->GetName();
if (messageName == "login_msg")
{
// extract message
CefRefPtr<CefListValue> args = message->GetArgumentList();
CefString strUser = args->GetString();
CefString strPassword = args->GetString(); m_pMainWnd->CEFLoginJsCallCPP(strUser,strPassword);//窗口类的成员函数 //如果函数有返回值也可以通过向Render发送消息传递
//send reply to render process
CefRefPtr<CefProcessMessage> outMsg = CefProcessMessage::Create("login_reply"); // Retrieve the argument list object.
CefRefPtr<CefListValue> replyArgs = outMsg->GetArgumentList(); // Populate the argument values.
replyArgs->SetSize();
replyArgs->SetInt(, ); // Send the process message to the renderer process.
browser->SendProcessMessage(PID_RENDERER, outMsg); return true;
} return false;
}

Browser进程处理完后向Render进程发了消息,The render process receives the IPC message处理

.h

 #ifndef _CEFBROWSERAPP_H_
#define _CEFBROWSERAPP_H_
#include "include/cef_app.h"
#include "CEFV8HandlerEx.h" class CCefBrowserApp
: public CefApp
, public CefBrowserProcessHandler
, public CefRenderProcessHandler
{
public:
CCefBrowserApp(); virtual ~CCefBrowserApp(); public:
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()OVERRIDE { return this; }; public:
// CefBrowserProcessHandler methods:
virtual void OnContextInitialized(); //CefRenderProcessHandler methods
virtual void OnWebKitInitialized(); CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE{ return this; } virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); virtual void OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); //收消息
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message); protected: CefRefPtr<CCEFV8HandlerEx> m_v8Handler; IMPLEMENT_REFCOUNTING(CCefBrowserApp);
};
#endif //_CEFBROWSERAPP_H_

.cpp

 #include "CefBrowserApp.h"
#include "stdafx.h" CCefBrowserApp::CCefBrowserApp()
:m_v8Handler(new CCEFV8HandlerEx)
{
} CCefBrowserApp::~CCefBrowserApp()
{
} void CCefBrowserApp::OnContextInitialized()
{
// do nothing here, because we will create browser in my own dialog
} void CCefBrowserApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
// Retrieve the context's window object.
CefRefPtr<CefV8Value> object = context->GetGlobal(); // Create the "NativeLogin" function.
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("NativeLogin", m_v8Handler);//第一个参数和SetValue参数保持一致,否则无法调用 // Add the "NativeLogin" function to the "window" object.
object->SetValue("NativeLogin", func, V8_PROPERTY_ATTRIBUTE_NONE); // Add the "register" function to the "window" object.
object->SetValue("register",CefV8Value::CreateFunction("register", m_v8Handler),V8_PROPERTY_ATTRIBUTE_NONE);
} void CCefBrowserApp::OnWebKitInitialized()
{
std::string app_code =
"var app;"
"if (!app)"
" app = {};"
"(function() {"
" app.GetId = function() {"
" native function GetId();"
" return GetId();"
" };"
"})();"; // Registered Javascript Function, which will be called by Cpp
" app.registerJavascriptFunction = function(name,callback) {"
" native function registerJavascriptFunction();"
" return registerJavascriptFunction(name,callback);"
" };" "})();"; CefRegisterExtension("v8/app", app_code, m_v8Handler);//第一个参数不能为空
} void CCefBrowserApp::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
m_v8Handler = nullptr;
} bool CCefBrowserApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)
{
const std::string& messageName = message->GetName();
if (messageName == "login_reply")
{
// extract message
CefRefPtr<CefListValue> args = message->GetArgumentList();
bool status = args->GetBool(); CefRefPtr<CefFrame> frame = browser->GetMainFrame(); if (status)
{
frame->ExecuteJavaScript("IsSuccess();", frame->GetURL(), );
} return true;
} return false;
}

 

2.JS CallBack

在OnContextCreated()函数中给window绑定函数

 // Create the "register" function.
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("register", m_v8Handler);//第一个参数和SetValue参数保持一致,否则无法调用 // Add the "register" function to the "window" object.
object->SetValue("register", func, V8_PROPERTY_ATTRIBUTE_NONE);

在Exectue()函数中处理

else if (name == "register")
{
if (arguments.size() == && arguments[]->IsFunction())
{
CefRefPtr<CefV8Value> callback_func_ = arguments[];
CefRefPtr<CefV8Context> callback_context_ = CefV8Context::GetCurrentContext(); callback_func_->ExecuteFunction(NULL, arguments);//执行回调函数 return true;
}
}

在HTML的JavaScript里这样写

  function myFunc()
{
// do something in JS.
alert("callback");
} //js CALLback
function CallBack()
{
window.register(myFunc);
}

3.C++ 调用 JS

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

  ///
// Execute a string of JavaScript code in this frame. The |script_url|
// parameter is the URL where the script in question can be found, if any.
// The renderer may request this URL to show the developer the source of the
// error. The |start_line| parameter is the base line number to use for error
// reporting.
///
/*--cef(optional_param=script_url)--*/
virtual void ExecuteJavaScript(const CefString& code,
const CefString& script_url,
int start_line) =;

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

 CefRefPtr<CefFrame> frame = m_handler->GetBrowser()->GetMainFrame();

 m_handler是我们自己定义的Handler对象

 /C++ 调用js方法
//frame->ExecuteJavaScript(L"Test();",frame->GetURL(),0);//提示框
//frame->ExecuteJavaScript(L"ModifyValue();",frame->GetURL(),0);//无参数函数
frame->ExecuteJavaScript(L"ModifyValue('巴萨牛逼');",frame->GetURL(),);//有参数函数
9 如果参数是可变的,可以这样
CString strJsCode;
strJsCode.Format(L"setInstallStatus('%s','%s','%d');", lpData->strId.c_str(), strStatus, nPercent);
其中setInstallStatus是js函数,它有三个参数

我在HMTL里写的

  function Test()
{
alert("js被C++非礼了");
} function ModifyValue( arr)
{
//document.getElementById("text").innerHTML = "被修改了"; alert(arr);
document.getElementById("text").innerHTML = arr;
}

最新文章

  1. C++11引用临时变量的终极解析
  2. std::list
  3. encodeURI(encodeURI(name)) ;文件上传
  4. 黄聪:MySql Host is blocked because of many connection errors; unblock with &#39;mysqladmin flush-hosts&#39; 解决方法(转)
  5. Git之 基本常用命令
  6. java.lang.NumberFormatException: For input string:&quot;filesId&quot;
  7. MySQL主主复制+LVS+Keepalived实现MySQL高可用性
  8. Elasticsearch中doc_value的认识
  9. MySQL注入与防御(排版清晰内容有条理)
  10. 团队作业8——Beta 阶段冲刺4th day
  11. http 四大特征
  12. Nginx系列4:用GoAccess实现可视化并实时监控access日志
  13. 【C++/类与对象总结】
  14. &lt;Spark&gt;&lt;Programming&gt;&lt;Key/Value Pairs&gt;&lt;RDD&gt;
  15. redis 部分操作
  16. Spring源码分析(十七)循环依赖
  17. jQuery学习-鼠标事件
  18. P2306 被yyh虐的mzc
  19. 修改easyui的easyloader的默认css目录路径
  20. 安装cx_Oracle 遇到的杂项问题

热门文章

  1. ios程序发布测试打包
  2. 【OpenWRT】【RT5350】【三】MakeFile文件编写规则和OpenWRT驱动开发步骤
  3. 使用&quot;关键词&quot;来整理自己的知识库
  4. android获取textview的行数
  5. 自定义EL表达式的函数
  6. jquery选择器和基本语句
  7. 安装eclipse的hadoop开发环境--2
  8. sprint 3 总结
  9. java类
  10. extjs 学习小窍门