CEF(Chromium Embedded Framework和JavaScript交互相互调用函数和设置数据
3.1 CEF和JavaScript交互
3.1.1 在CEF执行JavaScript脚本
3.1.2 窗口绑定方式实现CEF设置JavaScript的变量
3.1.3 扩展方式(Extension)实现CEF设置JavaScript的变量
3.1.4 窗口绑定方式实现CEF给JavaScript提供函数
3.1.5 Extension方式实现CEF给JavaScript提供函数
3.1 CEF和JavaScript交互
https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md
CEF使用的V8 JavaScript 引擎用于内部JavaScript实现,每一个frame都有JS上下文(context),为JS代码执行提供范围和安全。CEF暴露了很多JS特性可以和客户端程序进行交互。
3.1.1 在CEF执行JavaScript脚本
应用场景是需要在CEF中拦截一个URL请求,并把它重定向到另外一个URL,可以调用pFrame->ExecuteJavaScript来执行一个JavaScript脚本,实现跳转。当然也可以实现其他应用功能。
CefRefPtr<CefFrame> pFrame = browser->GetMainFrame();
std::string strurl = pFrame->GetURL().ToString();
std::string strname = pFrame->GetName().ToString();
pFrame->GetName().ToString().c_str());
if (pFrame->GetURL() == "https://10.19.141.75/portal/")
{
pFrame->ExecuteJavaScript("var param= { url:'https://10.19.141.75/ishelf-web/personalCenter' }; \
window.goToApp(param);\
var paramEx = { isExtend:true };\
window.extendScreen(paramEx);\
", pFrame->GetURL(), 0);
}
3.1.2 窗口绑定方式实现CEF设置JavaScript的变量
在CEF程序中,创建一个CefV8Value对象,获取上下文的窗口对象,注入窗口对象一个变量值,网页中就可以使用JavaScript获取这个变量值。窗口绑定在CefRenderProcessHandler::OnContextCreated()函数中。是上下文创建响应函数,窗口绑定方式在每次frame重新加载(context创建)时都会加载一遍,CEF程序可以在OnContextCreated()给每一个frame设置不同的变量值。
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) {
// Retrieve the context's window object.
CefRefPtr<CefV8Value> object = context->GetGlobal();
// Create a new V8 string value. See the "Basic JS Types" section below.
CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!");
// Add the string to the window object as "window.myval". See the "JS Objects" section below.
object->SetValue("myval", str, V8_PROPERTY_ATTRIBUTE_NONE);
}
JavaScript in the frame can then interact with the window bindings.
<script language="JavaScript">
alert(window.myval); // Shows an alert box with "My Value!"
</script>
3.1.3 扩展方式(Extension)实现CEF设置JavaScript的变量
Extension方式和窗口绑定方式类似,但是Extension方式是为每一个frame加载到上下文context,一旦加载变不能在修改,没有加载之前,DOM是不存在的,尝试范围这个值的DOM会出现崩溃。Extension方式是在CefRenderProcessHandler::OnWebKitInitialized()函数中用CefRegisterExtension() 函数注册的,是在初始化函数中实现的,所以对于每一个frame都是一样的。
void MyRenderProcessHandler::OnWebKitInitialized() {
// Define the extension contents.
std::string extensionCode =
"var test;"
"if (!test)"
" test = {};"
"(function() {"
" test.myval = 'My Value!';"
"})();";
// Register the extension.
CefRegisterExtension("v8/test", extensionCode, NULL);
}
JS中调用变量值
<script language="JavaScript">
alert(test.myval); // Shows an alert box with "My Value!"
</script>
3.1.4 窗口绑定方式实现CEF给JavaScript提供函数
(1) 自定义类实现CefV8Handler类,实现Execute接口,JavaScript执行函数后,会将函数名称、参数和返回值引用传递给Execute函数,Execute函数根据函数名去调用函数,函数的具体实现在Execute中,然后执行返回返回值。
class MyV8Handler : public CefV8Handler {
public:
MyV8Handler() {}
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) OVERRIDE {
if (name == "myfunc") {
// Return my string value.
retval = CefV8Value::CreateString("My Value!");
return true;
}
// Function does not exist.
return false;
}
// Provide the reference counting implementation for this class.
IMPLEMENT_REFCOUNTING(MyV8Handler);
};
(2)将函数名称设置到窗口对象,提供接受调用的handle
void MyRenderProcessHandler::OnContextCreated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) {
// Retrieve the context's window object.
CefRefPtr<CefV8Value> object = context->GetGlobal();
// Create an instance of my CefV8Handler object.
CefRefPtr<CefV8Handler> handler = new MyV8Handler();
// Create the "myfunc" function.
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
// Add the "myfunc" function to the "window" object.
object->SetValue("myfunc", func, V8_PROPERTY_ATTRIBUTE_NONE);
}
(3)JavaScript执行函数调用,就会进入Execute函数,返回返回值,alert会以弹窗形式展示结果。
<script language="JavaScript">
alert(window.myfunc()); // Shows an alert box with "My Value!"
</script>
3.1.5 Extension方式实现CEF给JavaScript提供函数
JavaScript调用CEF中的函数步骤:
(1)实现app类,继承与CefApp,重写OnWebKitInitialized,在OnWebKitInitialized函数内部使用字符串定义函数。CEF调用CefRegisterExtension函数向JavaScript注册函数,并提供处理调用的handler。
//CefClientApp.h
class CCefClientApp : public CefApp, public CefBrowserProcessHandler, CefRenderProcessHandler
{
public:
CCefClientApp();
~CCefClientApp();
//所有的CEF接口 都需要重载GetXXXHandler,并且return this,才会有效
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override { return this; }
//===========CefRenderProcessHandler
virtual void OnWebKitInitialized() override;
private:
CefRefPtr<CCEFV8HandlerEx> v8Handler_;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(CCefClientApp);
private:
};
//CefClientApp.cpp
void CCefClientApp::OnWebKitInitialized()
{
//MessageBox(NULL,L"OnWebKitInitialized\n",0,0);
std::string app_code =
//-----------------------------------
//声明JavaScript里要调用的Cpp方法
"var app;"
"if (!app)"
" app = {};"
"(function() {"
// jsInvokeCPlusPlus 实例函数
" app.jsInvokeCPlusPlus = function(v1, v2) {"
" native function jsInvokeCPlusPlus();"
" return jsInvokeCPlusPlus(v1, v2);"
" };"
//函数
" app.jsTransform = function(v1) {"
" native function jsTransform();"
" return jsTransform(v1);"
" };"
"})();";
// Register app extension module
// JavaScript里调用app.jsInvokeCPlusPlus时,就会去通过CefRegisterExtension注册的CefV8Handler列表里查找
// 找到"v8/app"对应的CCEFV8HandlerEx,就调用它的Execute方法
// 假设v8Handler_是CCefClientApp的一个成员变量
//v8Handler_ = new CCEFV8HandlerEx();
CefRegisterExtension("v8/app", app_code, v8Handler_);
}
(2)JavaScript调用函数
<html>
<script>
app.jsInvokeCPlusPlus("123","xyz");
app.jsTransform("hello world");
</script>
</html>
(3) handler的Execute函数接收调用响应,根据函数名称判断是调用哪个函数,获取参数调用函数。
//CEFV8HandlerEx.h
CefV8Handler
public:
public:
CefString
name
CefRefPtr
CefV8Value
object
CefV8ValueList
arguments
CefRefPtr
CefV8Value
retval
CefString
exception
override
private:
std
map
std
pair
std
string
std
pair
CefRefPtr
CefV8Context
CefRefPtr
CefV8Value
CallbackMap
CallbackMap callback_map_
public:
CCEFV8HandlerEx
};
//CEFV8HandlerEx.cpp
//JS调用C++函数的回调
CCEFV8HandlerEx
CefString
name
CefRefPtr
CefV8Value
object
CefV8ValueList
arguments
CefRefPtr
CefV8Value
retval
CefString
exception
{
name
arguments
CefString strParam1
arguments
CefString strParam2
arguments
TCHAR szBuffer
szBuffer
szBuffer
strParam1
strParam2
szBuffer
MB_OK
retval
CefV8Value
retval
CefV8Value
name
L
CefString strParam1
arguments
TCHAR szBuffer
szBuffer
szBuffer
strParam1
szBuffer
MB_OK
}
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix