CEF:C++和JS交互

2023-05-16

C++和JS交互V8原理:https://github.com/fanfeilong/cefutil/blob/master/doc/content_register_v8_extension.md

CEF一个页面的框架如下图所示:

在这里插入图片描述

CefBrowser:一个普通的浏览器页面(HTML)

CefFrame:每一个页面都由至少一个frame组成,最顶层的为mainframe

context:JS执行环境,每个frame都有自己独立的context,CEF中使用V8JavaScriptEngine解析和执行JS代码

CEF 中的JavaScript

  • CEF 利用 V8 JS 引擎来实现 JS。
  • 浏览器中的每一个 frame 都有自己的 JS 上下文,JS 只能在该上下文中执行。
  • JS 只能在渲染进程中的 TID_RENDERER 线程中执行。
  • 有关 JS 回调的接口都包含在 CefRenderProcessHandler 中,因此我们要实现这个接口来对 JS 进行扩展。这个接口一般由 CefApp 实现。

C++调用JS

事实上cef本身支持直接执行js(js代码或者js函数)的接口,原型如下:

  ///
  // 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) = 0;

  ///class CefV8Value,此时可以获取返回值
  // Execute the function using the current V8 context. This method should only
  // be called from within the scope of a CefV8Handler or CefV8Accessor
  // callback, or in combination with calling Enter() and Exit() on a stored
  // CefV8Context reference. |object| is the receiver ('this' object) of the
  // function. If |object| is empty the current context's global object will be
  // used. |arguments| is the list of arguments that will be passed to the
  // function. Returns the function return value on success. Returns NULL if
  // this method is called incorrectly or an exception is thrown.
  ///
  /*--cef(optional_param=object)--*/
  virtual CefRefPtr<CefV8Value> ExecuteFunction(
      CefRefPtr<CefV8Value> object,
      const CefV8ValueList& arguments) = 0;
1.ExecuteJavaScript 可以直接执行JS函数,但是没有办法获取返回值。
//@param js js代码或者函数,
//eg:js="add(1,2)"
void CBrowserHandler::ExeJs(const CefString &js)
{
	...
	browser->GetMainFrame()->ExecuteJavaScript(js, L"", 0);
	...
}

#######################################C++调用JS测试,直接通过ExeJs("add(10,20)")调用JS函数####################
//JS:
function call_add(val1,val2)
{
	alert(window.add(val1,val2));
}

//C++
...
if (m_browser_app)
	m_browser_app->ExeJs(L"call_add(10,20)");
...

在这里插入图片描述

2、ExecuteFunction需要配合V8Context一起执行。执行之前需要context->Enter(),完成之后context->Exit()

V8Context分为两种情况:

  1. 使用自己保存的V8Context (Render进程使用)
  2. 使用全局的V8Context (Render进程使用)
//获取局部保存的Context,并且执行Js函数
CefRefPtr<CefV8Context> context = m_map_call_back[iMsgID].first;
CefRefPtr<CefV8Value> call_back = m_map_call_back[iMsgID].second;
if (context && call_back)
{
	context->Enter();
	if (context->GetBrowser())
	{
		CefV8ValueList call_arguments;
		call_arguments.push_back(CefV8Value::CreateString(args->GetString(2)));
		if (call_back->IsFunction())
			call_back->ExecuteFunction(NULL, call_arguments);
	}
	context->Exit();
}

//获取全局的JS函数并且执行GetV8Context只能在render进程中使用
CefRefPtr<CefV8Context> context = browser->GetMainFrame()->GetV8Context();
context->Enter();
CefRefPtr<CefV8Value> global = context->GetGlobal();
if (global)
{
	//获取全局函数js_handler_call_back,并且执行js_handler_call_back
	CefRefPtr<CefV8Value> call_back = global->GetValue("js_handler_call_back");
	if (call_back && call_back->IsFunction())
	{
		CefV8ValueList call_arguments;
		call_arguments.push_back(CefV8Value::CreateString(args->GetString(2)));
		if (call_back->IsFunction())
			call_back->ExecuteFunction(NULL, call_arguments);
	}
}
context->Exit();

本次demo中,我们预定如果设置回调,则第一个参数必须是函数指针,否则我们将使用默认的全局回调函数js_handler_call_back回调数据。

	function register(){
		MyMath.register(call_back);
	}
	
	function MyTimer(){
		MyMath.Timer(1);
	}

	<p onclick="register()">this is a register function</p>
	<button onclick="MyTimer()">启动Timer(1)</button>

在这里插入图片描述

JS调用C++(Render进程实现)

绑定值和函数到Window对象

在CefRenderProcessHandler::OnContextCreated() 中绑定一些值给 JS 的 window 对象。

class CRenderApp :public CefApp, public CefRenderProcessHandler
void CRenderApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
	CefRefPtr<CefFrame> frame,
	CefRefPtr<CefV8Context> context)
{
 	CEF_REQUIRE_RENDERER_THREAD();
 	
	//添加全局成员window的成员
	CefRefPtr<CefV8Value> object = context->GetGlobal();
	CefRefPtr<CefV8Value> v8Value = CefV8Value::CreateString("c++ value");
	object->SetValue("MyValue", v8Value, V8_PROPERTY_ATTRIBUTE_NONE);

	//添加全局函数,add函数实现在CJSHandler里面
	CefRefPtr<CefV8Handler> add_handler = new CJSHandler(this);
	CefRefPtr<CefV8Value> add_func = CefV8Value::CreateFunction("add", add_handler);
	object->SetValue("add", add_func, V8_PROPERTY_ATTRIBUTE_NONE);
	//此时支持window.MyValue 属性,和window.add函数
}

bool CJSAdd::Execute(const CefString& name,CefRefPtr<CefV8Value> object,const CefV8ValueList& arguments,CefRefPtr<CefV8Value>& retval,CefString& exception)
{
	//function add
	if (name == "add")
	{
		int32  val2 = arguments[0]->GetIntValue();
		int32  val1 = arguments[1]->GetIntValue();
		int32 sum = val1 + val2;
		retval = CefV8Value::CreateInt(sum);
		return true;
	}
	return false;
}

#######################################JS测试,直接通过window.MyValue访问####################
<script>
function show(){
	alert(window.MyValue);
}

function call_add(val1,val2){
	alert(window.add(val1,val2));
}
</script>

在这里插入图片描述
在这里插入图片描述

扩展JS

在 CefRenderProcessHandler::OnWebKitInitialized() 中将 JS 脚本注入到 V8 中。
只能被Render 进程的调用

扩展值和函数

更详细的demo可以参考CefRegisterExtension 类的说明

void CRenderApp::OnWebKitInitialized()
{
	CEF_REQUIRE_RENDERER_THREAD();

	// Define the extension contents.
	std::string extensionCode =
		"var MyMath;"
		"if (!MyMath)"//如果没有MyMath对象,则定义一个MyMath对象
		"  MyMath = {};"
		"(function() {"
		"  MyMath.add = function(num1, num2) {"//定义一个MyMath的add函数,参数顺序为外部js调用顺序
		"    native function add();"//native 函数,不带参数
		"    return add(num1, num2);"//add在CefV8Handler具体实现,参数顺序为CefV8Handler 中的参数顺序
		"  };"
		"  MyMath.hellow = 'Hello JS!';"//定义一个MyMath的成员变量
		"})();";

	CefRefPtr<CefV8Handler> add_handler = new CJSAdd();
	// Register the extension.
	CefRegisterExtension("v8/test", extensionCode, add_handler);
}

###################JS测试,直接通过MyMath.add调用函数,MyMath.hellow获取成员变量####################
function CallMyMathAdd()
	{
		v1 = document.getElementById('num1').value;
		v2 = document.getElementById('num2').value;
		alert(MyMath.add(Number(v1),Number(v2)));
	}
	
	function ShowMyMathHellow()
	{
		alert(MyMath.hellow);
	}

在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CEF:C++和JS交互 的相关文章

  • cef中js与C++交互

    cefquery方式交互 前端使用 window span class token punctuation span span class token function cefQuery span span class token punc
  • CEF方面的研究(五) CEF中C++与JS交互

    C 43 43 与JS的交互 xff0c 相信不用多说 xff0c 必是精髓 在写这篇博客之前 xff0c 我不得不说之前遇到的一个问题 xff1a 不管怎么搞 xff0c 都不能回调到C 43 43 函数中 原因是什么呢 xff1f 我没
  • CEF:C++和JS交互

    C 43 43 和JS交互V8原理 xff1a https github com fanfeilong cefutil blob master doc content register v8 extension md CEF一个页面的框架如
  • Go 在 Windows 上用户图形界面 GUI 解决方案 Go-WinGUI 国产(使用cef 内核)

    Go 在 Windows 上用户图形界面 GUI 解决方案 Go WinGUI 国产 xff08 使用cef 内核 xff09 参考文章 xff1a xff08 1 xff09 Go 在 Windows 上用户图形界面 GUI 解决方案 G
  • CEF中JavaScript与C++交互

    在CEF里 xff0c JS和Native xff08 C C 43 43 xff09 代码可以很方便的交互 xff0c 这里https bitbucket org chromiumembedded cef wiki JavaScriptI
  • 一步步CEF(2)之编译ceflicent

    一步步CEF xff08 1 xff09 之编译libcef dll wrapper lib已经提供了c 43 43 的静态库 xff0c 这次要将cefclient编译出来 这里要说明一下 xff0c 如果仅仅将cefclient编译的话
  • CEF(Chromium Embedded Framework)使用说明书

    CEF使用说明书 目录 1 前言 1 1 CEF的作用 1 2 CEF的下载和编译 1 3 CEF结构 1 3 1 CEF进程和窗口之间的结构关系 1 3 2 Renderer进程的实现结构 1 3 3 browser进程的实现结构 1 4
  • cef相关

    一 应用 在Windows下进行浏览器相关的开发 1 使用IE相关的接口 IE控件等进行开发 Windows提供了丰富的接口用起来也是非常方便的 缺点 例如XP还有很多人使用 它的IE版本可能比较旧 对一些新的网页特性可能支持的不好 2 使
  • cef浏览器加载过程实测ILoadHandler和IRequestHandler

    针对方法GetResourceRequestHandler 获取资源请求过程中 会多次发生请求 不知道何时加载完的问题 IRequestHandler 没有了OnResourceLoadComplete 和OnBeforeResourceL
  • 01-Chrome架构:仅仅打开了1个页面,为什么有4个进程

    在开始之前 我们一起看下 Chrome打开一个页面需要启动多少进程 你可以点击Chrome浏览器右上角的 选项 菜单 选择 更多工具 子菜单 点击 任务管理器 这将打开Chrome的任务管理器的窗口 如下图 和Windows任务管理器一样
  • Cef经典N大问题

    1 cef启动 退出的时候怎么崩溃了 答 如果是启动时崩溃 请看资源目录是否文件都齐全 退出的话见https github com fanfeilong cefutil blob master doc CEF Close md 如果是cen
  • 自编译已集成视频播放功能CEF3.3239版本库 (官方版本编译类似)详解介绍步骤(含编译错误解决)

    工具及编译环境 VS2015 Cmake cmake官网 https cmake org CEF工程官网 https cef builds spotifycdn com index html 1 下载CEF源码 下面的源码是已经集成了播放视
  • cef3:禁止win10高dpi下cef对内部网页进行缩放

    cef对内部网页进行缩放
  • Linux下编译CEF源码及交叉编译

    Linux下编译CEF chromium源码及交叉编译 官方编译文档 https bitbucket org chromiumembedded cef wiki MasterBuildQuickStart markdown header l
  • Qt浏览器开发:关于CEF开发知识点以及QCef开发原理与使用

    开发环境 VS2015 Qt5 9 关于CEF CEF全称是Chromium Embedded Framework 它是Chromium的Content API的封装库 基于Google Chromium 的开源项目 而Google Chr
  • QCefView源码优化

    QCefView项目源码的构建部分这里就不赘述了 有问题的朋友可以回到 QCefView 1 CMAKE项目 库文件生成和项目测试 查看相关介绍 本次优化主要包括以下几个部分 1 设置部分 关闭代理服务器 关闭同源策略 使用系统flash等
  • qt集成cef QWidget

    编译libcef dll wrapper 假设你已经编译出了libcef dll wrapper lib Debug和Release版本 并且对应版本的程序集类型分别是 MDd和MD qt的运行时库是MDd类型的 因此cef3编译的时候也应
  • xe7 安装chrome组件(CEF4Delphi)

    缘起 大屏项目需要用到chrome组件 但为了实现firemonkey的矢量和强大的图形功能 所以只能重新在xe7中安装chrome组件 碰到了一些问题 都一 一化解了 将整个过程记录下来 以供大家采用 1 下载CEF4Delphi mas
  • cef编译

    按照大神的一遍过 具体过程非常详细 链接https kefong blog csdn net article details 119908780 spm 1001 2101 3001 6650 2 utm medium distribute
  • 禁用CEF跟随系统的DPI缩放

    方法1 为程序添加启动参数 high dpi support 1 force device scale factor 1 1 在桌面上右键Chrome图标 选择属性 2 在目标一栏中增加自定义参数 force device scale fa

随机推荐