CEF3里JS回调C++有两种模式,1.单进程模式、2.多进程模式
一、单进程模式
让自己的SimpleApp来继承 CefRenderProcessHandler这个抽象类,然对其下面的纯虚函数进行重写,以达到声明JS函数的作用
simple_app.h:
class SimpleApp : public CefApp,
public CefBrowserProcessHandler,
public CefRenderProcessHandler {
// CefRenderProcessHandler methods:
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler()
OVERRIDE {
return this;
}
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
simple_app.cc:
#include "simple_V8Handler.h"
void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
// The var type can accept all object or variable
CefRefPtr<CefV8Value> pV8 = context->GetGlobal();
// bind function
CefRefPtr<CSimpleV8Handler> pJsHandler(new CSimpleV8Handler());
CefRefPtr<CefV8Value> pFunc = CefV8Value::CreateFunction(CefString("ShowJsInfo"), pJsHandler);
pV8->SetValue(CefString("ShowJsInfo"), pFunc, V8_PROPERTY_ATTRIBUTE_NONE);
}
新建simple_V8Handler.cpp和simple_V8Handler.h文件用于处理函数请求调用
simple_V8Handler.h:
#pragma once
#include "include/cef_v8.h"
class CSimpleV8Handler : public CefV8Handler
{
public:
CSimpleV8Handler() {};
~CSimpleV8Handler() {};
public:
virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE;
private:
IMPLEMENT_REFCOUNTING(CSimpleV8Handler);
};
simple_V8Handler.cpp:
#include "simple_V8Handler.h"
bool CSimpleV8Handler::Execute(
const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval, //这里是设置JS返回值的地方
CefString& exception)
{
if (name == CefString("ShowJsInfo"))
{
if (arguments.size() == 1 && arguments[0]->IsString())
{
CefString arg = arguments[0]->GetStringValue();
//注意要把JS发回来的文本的0xA0(EASCII码的空格'\xa0')替换成0x20(ASCII码的空格'\x20')
std::wstring strInfo(L"这是 JavaScript 发来的数据:");
strInfo += arg.ToWString();
::MessageBoxW(0, strInfo.c_str(), L"C++ 提示框", MB_OK);
//设置返回值演示
//retval = CefV8Value::CreateInt(1);
return true;
}
}
return false;
}
二、多进程模式
请先完成单进程JS回调代码的书写后,再修改为多进程JS回调。
先介绍一下CEF3多进程的通讯模式
SimpleApp类里继承的CefRenderProcessHandler主要负责Render进程,
其中Render进程接收到的消息都会在CefRenderProcessHandler::OnProcessMessageReceived
SimpleHandler类里继承的CefClient主要负责Browser进程,
其中Browser进程接收到的消息都会在CefClient::OnProcessMessageReceived
修改simple_V8Handler.h:
#pragma once
#include "include/cef_v8.h"
class CSimpleV8Handler : public CefV8Handler
{
public:
CSimpleV8Handler(CefRefPtr<CefBrowser> browser) //改动构造函数
{
m_Browser = browser;
};
~CSimpleV8Handler() {};
public:
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) OVERRIDE;
//新增一个执行JS的函数
void Execute(const CefString& name, CefRefPtr<CefListValue> arguments, CefRefPtr <CefValue> & retValue);
private:
CefRefPtr<CefBrowser> m_Browser; //新增保存CEF3窗口句柄变量
IMPLEMENT_REFCOUNTING(CSimpleV8Handler);
};
修改simple_V8Handler.cpp:
#include "simple_V8Handler.h"
bool CSimpleV8Handler::Execute(
const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
//将参数列表CefV8ValueList转成CefListValue类型
CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(name);
CefRefPtr<CefListValue> args = msg->GetArgumentList();
for (int i = 0; i < arguments.size(); i++)
{
if (arguments[i]->IsBool())
{
args->SetBool(i, arguments[i]->GetBoolValue());
}
else if (arguments[i]->IsInt())
{
args->SetInt(i, arguments[i]->GetIntValue());
}
else if (arguments[i]->IsString())
{
args->SetString(i, arguments[i]->GetStringValue());
}
else if (arguments[i]->IsDouble())
{
args->SetDouble(i, arguments[i]->GetDoubleValue());
}
}
//可在Render进程处理的JS函数
if (name == CefString("ShowJsInfo"))
{
if (arguments.size() == 1 && arguments[0]->IsString())
{
CefString arg = arguments[0]->GetStringValue();
//注意要把JS发回来的文本的0xA0(EASCII码的空格'\xa0')替换成0x20(ASCII码的空格'\x20')
std::wstring strInfo(L"这是 JavaScript 发来的数据:");
strInfo += arg.ToWString();
::MessageBoxW(0, strInfo.c_str(), L"C++ 提示框", MB_OK);
//设置返回值演示
//retval = CefV8Value::CreateInt(1);
return true;
}
}
//其余需要在Browser进程处理的JS函数就转发到Browser进程去
if (CefCurrentlyOn(TID_RENDERER))
{
// Execute on the browser process.
m_Browser->SendProcessMessage(PID_BROWSER, msg); //转发到Browser进程去
return true;
}
return false;
}
void CSimpleV8Handler::Execute(const CefString& name, CefRefPtr<CefListValue> arguments, CefRefPtr <CefValue> & retValue)
{
//执行需要在Browser进程处理的JS函数
if (name == CefString("ShowInBrowserJS"))
{
if (arguments->GetSize() == 1)
{
CefString arg = arguments->GetString(0);
//注意要把JS发回来的文本的0xA0(EASCII码的空格'\xa0')替换成0x20(ASCII码的空格'\x20')
std::wstring strInfo(L"这是 JavaScript 发来的数据:");
strInfo += arg.ToWString();
::MessageBoxW(0, strInfo.c_str(), L"C++ 提示框", MB_OK);
return true;
}
}
}
修改simple_app.cc:
#include "simple_V8Handler.h"
void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
// The var type can accept all object or variable
CefRefPtr<CefV8Value> pV8 = context->GetGlobal();
// bind function
CefRefPtr<CSimpleV8Handler> pJsHandler(new CSimpleV8Handler(browser)); //构造函数传参
CefRefPtr<CefV8Value> pFunc = CefV8Value::CreateFunction(CefString("ShowJsInfo"), pJsHandler);
pV8->SetValue(CefString("ShowJsInfo"), pFunc, V8_PROPERTY_ATTRIBUTE_NONE);
}
修改simple_handler.h:
//新增继承虚函数
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message) OVERRIDE;
修改simple_handler.cc:
#include "simple_V8Handler.h"
bool SimpleHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
{
CEF_REQUIRE_UI_THREAD();
//Browser进程接收到的消息都会在这里
// TODO:
//无用消息
if (!message->IsValid())
{
return false;
}
//执行函数
CefString jsFuncName = message->GetName();
CefRefPtr<CefListValue> jsFuncArgs = message->GetArgumentList();
CSimpleV8Handler tempV8(browser);
CefRefPtr<CefValue> retValue; //返回值,这里只接收 不发回Render进程
tempV8.Execute(jsFuncName, jsFuncArgs, retValue);
return false;
}