cef的一些使用方法

cef中提供了一个内置的chome浏览器,对于C/S中使用B/S的方法提供了很大帮助,.net中 自带的webbrowser对IE浏览器有要求,如果客户端的IE版本较低,对于jquery中的方法部分不支持,所以cef就成为了B/S开发C/S的一个利器。

由于项目.net版本原因,用到的是CefSharp-cefsharp-47版本。

一 CEF环境搭建

具体的搭建过程就不多说了,网上都有教程,搜一搜就出来了

下载cef源码后,发现example下的dll有很多个,在网上查了资料后整理了一个大概项目中引用需要的dll文件

1) libcef.dll

2) icudtl.dat

3) devtools_resources.pak(这个必须要的,如果没有的话,页面上会出现好多类似代码的东西)

4) CefSharp.WinForms.dll

5) CefSharp.dll

6) CefSharp.Core.dll

7) CefSharp.BrowserSubprocess.exe

8) CefSharp.BrowserSubprocess.Core.dll

9) locales文件夹下的东西(都是类似于字符集编码的东西)

10)一些pak文件(这些文件是用来控制cef中的样式文件,如cef_100_percent.pak这个如果没有的话,html中的width=100%在窗体最大化的时候就不起作用)

CEF代码编写

1 简单的展现页面

ChromiumWebBrowserm_chromeBrowser =null;

m_chromeBrowser= newChromiumWebBrowser("www.baidu.com");

注意ChromiumWebBrowser的构造方法只有一个,必须传入一个url,如果不需要就传""就行

load函数只能加载urlhtml串不行,得用下面的loadhtml

2 直接加载html串

m_chromeBrowser.LoadHtml(htmlStr);

注意,这里的LoadHtml是采用的C#中的扩展方法写的。所谓的C#扩展方法就是相当于C#的一个语法炮弹,就是普通的静态类静态方法,需要把对象传入的。

这里必须usingCefSharp; using CefSharp.WinForms;如果只usingCefSharp.WinForms,那么new出来的ChromiumWebBrowser对象只能.出来Load方法,所有的扩展方法如LoadHtml都是无法点出来的。

m_chromeBrowser.LoadHtml("Helloworld","http://customrendering/");

两个参数,前面的那个是要显示在界面上的,后面的网址的作用暂时还没研究出来,应该是如果有服务器端的话,拼接服务器端的地址的(由于项目中并不是传统的服务器端模式,而是每个终端都是服务器加客户端 的模式,所以暂时没有研究,希望 大神指导下)

注意:网址的一定不能写成"",要不然会报错,直接程序就挂了,好像www.开头的也不行,只能用http://开头的网址用

3 执行提交类的操作(还没调研是否是异步的,好像都是同步的)

1 html肯定是该咋写咋写了,主要是js,例如:

function test1()

{

         varresult = winformObj.someFunction();

         aler(result);

}

其中winformObj这个对象是由C#中定义的,所以就相当于这里用了js然后执行了一个C#的对象的方法。

2 定义winformObj

publicclassJavaScriptInteractionObj

{

            [JavascriptIgnore](这个标签是cef自带的,现在还不知道有啥用)

        publicChromiumWebBrowser m_chromeBrowser {get;set;}

 

            [JavascriptIgnore]

        publicvoidSetChromeBrowser(ChromiumWebBrowser b)

        {

           m_chromeBrowser = b;

        }

                  

                   //对应着js中调用的那个方法名称

            public string someFunction(){

                   //...................

                   }

}

3 绑定对象(这个不是在JavaScriptInteractionObj类中,而是C#客户端中用到的页面进行绑定的)

m_jsInteractionObj = newJavaScriptInteractionObj();

m_jsInteractionObj.SetChromeBrowser(m_chromeBrowser);

// Register the JavaScriptInteractionObj class withJS

m_chromeBrowser.RegisterJsObject("winformObj",m_jsInteractionObj);


4 C#代码中执行js脚(这个是网上下的教程中的,忘了是哪个大神些的了,就直接拿过来用 了)

方式1. ExecuteScriptAsync 方法使用方式与 js 的 eval方法一样,异步执行,无返回值

 

// xxx为js的方法名称
wb.ExecuteScriptAsync("xxx()"); 
// 为 js 的变量jsVar赋值 'abc'
wb.ExecuteScriptAsync("jsVar='abc'"); 

 

(但为毛只能将js传入到webbrowser中呢,难道不能直接调用吗?加载的时候应该已经加载到了js了啊,难道没加载到js?貌似找不到相对路径哎,必须得弄成绝对路径,要不找不到

)

 

方式2.EvaluateScriptAsync 方法使用方式与 js 的 eval方法一样,异步执行,有返回值。

Task t =wb.EvaluateScriptAsync("callTest2()");
// 等待js 方法执行完后,获取返回值

t.Wait();
// t.Result 是 CefSharp.JavascriptResponse 对象
// t.Result.Result 是一个 object 对象,来自js的 callTest2() 方法的返回值
if(t.Result.Result != null)
{
   MessageBox.Show(t.Result.Result.ToString());
}

 

执行一段js脚本

           m_chromeBrowser.LoadHtml("Helloworld","http://customrendering/");

 

            varscript ="document.body.style.backgroundColor = 'red';";

 

           m_chromeBrowser.ExecuteScriptAsync(script);

 

 

调用一段js方法的内容

           m_chromeBrowser.LoadHtml("Helloworld","http://customrendering/");

 

            StringBuilder sb =newStringBuilder();

           sb.AppendLine("function tempFunction() {");

           sb.AppendLine("    var w = window.innerWidth;");

           sb.AppendLine("    var h = window.innerHeight;");

           sb.AppendLine("");

           sb.AppendLine("    return w*h;");

           sb.AppendLine("}");

           sb.AppendLine("tempFunction();");

 

            vartask = m_chromeBrowser.EvaluateScriptAsync(sb.ToString());

 

           task.ContinueWith(t =>

            {

               if (!t.IsFaulted)

               {

                   var response = t.Result;

 

                   if ( response.Success ==true)

                   {

                       MessageBox.Show( response.Result.ToString() );

                   }

                }

            }, TaskScheduler.FromCurrentSynchronizationContext());

 

                            demo2

            //Step 01: create a simple html page (include jquery so we have access to jsonobject

            StringBuilder htmlPage =newStringBuilder();

           htmlPage.AppendLine("");

           htmlPage.AppendLine("");

           htmlPage.AppendLine("");

           htmlPage.AppendLine("");

           htmlPage.AppendLine("Hello world2");

           htmlPage.AppendLine("");

 

            //Step 02: Load the Page

           m_chromeBrowser.LoadHtml(htmlPage.ToString(),"http://customrendering/");

 

            //Step 03: Execute some ad-hoc JS that returns an object back to C#

            StringBuilder sb =newStringBuilder();

           sb.AppendLine("function tempFunction() {");

           sb.AppendLine("    //create a JS object");

            sb.AppendLine("    var person = {firstName:'John',lastName:'Maclaine', age:23, eyeColor:'blue'};");

           sb.AppendLine("");

           sb.AppendLine("    //Important: convert object to string before returning to C#");

           sb.AppendLine("    return JSON.stringify(person);");

           sb.AppendLine("}");

           sb.AppendLine("tempFunction();");

 

            vartask = m_chromeBrowser.EvaluateScriptAsync(sb.ToString());

 

           task.ContinueWith(t =>

            {

                if(!t.IsFaulted)

               {

                   // Step 04: Recieve value from JS

                   var response = t.Result;

 

                   if (response.Success ==true)

                   {

                       //Use JSON.net to convert to object;

                       MessageBox.Show(response.Result.ToString());

                   }

               }

            }, TaskScheduler.FromCurrentSynchronizationContext());

5 CEF中的一些容易出错的地方及坑吧(只能这么说了,在项目中碰到某些坑完全找不到原因,只能硬着头皮去扒源码看看,结果也是一知半解的)

1 js执行时间,在cef中如果调用js中的某些方法,可能会出现有时能调用成功,有时调用失败的情况,调试后发现这完全就是还是拿C/S的思路去写B/S代码的错误。浏览器加载js都是要有时间的撒,在C#中要调用,必须得等js加载完全。f12后,发现了几个事件 formloadend loadstatechange等,最后用的是在cef的formloadend 事件中调用就好了

2 如果有两个窗口的pannel同时加载了cef,然后执行一个窗口的close,就抛一个空指针错误,这个调了好久,最后连着源码发现cef其实起了一个线程在不停的监控cef的状态,其中在CefSharp.WinForms.Internals.ControlExtensions中的方法

        public static bool IsActiveControl(this Control control)
        {
            Control activeControl = control.FindForm().ActiveControl;
            while (activeControl != null(这句话是自己加上的)
                   && (activeControl is ContainerControl)
                   && !Object.ReferenceEquals(control, activeControl))
            {
                var containerControl = activeControl as ContainerControl;
                activeControl = containerControl.ActiveControl;
            }
            return Object.ReferenceEquals(control, activeControl);
        }

       调试发现 activeControl是null,这个方法是不停的被线程监控执行的,猜想应该是窗口关闭后,里面的panel什么的控件都dispose了,所以activeControl就是null了,具体的为啥也没细研究,有空研究研究,加上非空判断后就ok了(嘿嘿,就是这么的不求上进)

3 调用js重复调用

js是在formloadend中写的,但写完js后猜想是又引起了cef的加载,所以不停的加载(上面说了cef起了一个线程在不停的看状态),所以如果在formloadend中写调用js的事件时,要记的调的时候+=,调完了后要-=,这样就不会重复调用了

6 漏了一个关键的信息,cef用完后必须调用cef.shutdown来结束其所依赖的exe进程,否则程序会出现进程关不掉的情况

由于只是个菜鸡,所以大概的方向就是能够这个项目实现就ok,也没咋细研究,欢迎各路大神研究cef后指出错误!


你可能感兴趣的:(C#)