cefglue埋坑记录

时间:2021-11-14 11:34:02

很少写博客,写的不好,请多多包含,主要是记录工作中的一些问题,和园子里朋友一起讨论学习。

写埋坑记录之前,我先介绍下为什么会使用这个webkit内核的浏览器组件,我是wpf项目使用富文本编辑器,话说wpf平台里面原生支持比较好的富文本编辑器还真没用,还有一个原因我这个编辑器还要集成数学公式的输入输出,那就必须要自定义控件显现,考虑到web端的通用,最后决定用百度编辑器UEDITORjq插件。

cefglue底层是C/C++项目,主要是通过平台调用p/invoke实现。cefglue代码下载地址是:https://bitbucket.org/xilium/xilium.cefglue/overview,动态链接库下载地址:http://xilium.bitbucket.org/cefglue/,注意要FQ。

代码结构我就不说了,里面有winform wpf 等版本,当然主要的功能已经实现,如果需要特定功能需额外定制。出于项目需要,我主要实现了有一下几个功能。

1.执行js获取返回值。

2.js回调后台方法。

获取返回值,CEF使用V8引擎实现javascript操作。浏览器中的每一个Frame都有它自己的JS上下文,上下文提供一种线程安全机制来执行页面上的JS代码
JS运行在独立的渲染进程中,同渲染线程同一个线程。渲染进程的中的主线程使用TID_RENDERER来标示,所有的V8操作必须在这个线程上执行。JS执行相关的回调通过CefRenderProcessHandler暴露出来实现回调。主要代码:

protected override bool OnProcessMessageReceived(CefBrowser browser, CefProcessId sourceProcess, CefProcessMessage message)
{
string[] items = message.Name.Split(new char[] { '|' });
if (items.Length == 0) return false;

switch (items[0])
{
case "EvaluateScript":
{
CefV8Value value = CefV8Value.CreateString("t");
CefV8Exception exp;
browser.GetMainFrame().V8Context.TryEval(items[1], out value, out exp);
CommonObj.JsEvaResult = null;
if (value == null)
{
CommonObj.flag = true;
return true;
}
else
if (value.IsArray)
{

}
else
if (value.IsString)
{
CommonObj.JsEvaResult = value.GetStringValue();
}
else
if (value.IsInt)
{
CommonObj.JsEvaResult = value.GetIntValue();
}
else
if (value.IsDouble)
{
CommonObj.JsEvaResult = value.GetDoubleValue();
}
else
if (value.IsBool)
{
CommonObj.JsEvaResult = value.GetBoolValue();
}
else
if (value.IsDate)
{
CommonObj.JsEvaResult = value.GetDateValue();
}
CommonObj.flag = true;
return true;
}

从写CefRenderProcessHandler基类OnProcessMessageReceived方法,此处一定要注意,在外部多线程环境里面执行,一定要封送渲染线程上下文环境,要不无法回调。

2.js回调后台,第一种方法:网上有很多朋友通过ajax请求实现,原理是截获请求报文,获取请求参数,实现动态反射。第二种方法:浏览器窗口中的每个页面都有V8上下文。上下文包含了页面中所有的变量、对象和方法,如果我们注册了CefV8HandlerV8上下文处理器,并且在本地代码中保存当前上下文的引用和JS函数那么可以轻松实现js回调。

主要思路,代码太多,如果需要代码的可以给我留言:

1.生成本地js和页面js映射。2.实现V8引擎,从写Excute方法。3.创建js回调类,包含页面js函数声明方法,主要是为了V8Excute方法里面动态反射调用。

到现在为止,js回调后台方法实现,但是新的问题来了。没办法确定是哪个浏览器里面的js触发的回调。我的做法是,在每个浏览器加载页面完成的时候生成一个GUID标识浏览器对象id,执行页面js函数,写入到页面隐藏域里面,便于后面的回调传入这个标识ID。

目前项目中用到的就这几个功能,写的不好不要拍砖,需要源代码的可以给我留言。