zoukankan      html  css  js  c++  java
  • Cef框架的使用:内嵌Chromium内核浏览器

    Chromium Embedded Framework (CEF)是个基于Google Chromium项目的开源Web browser控件,支持Windows, Linux, Mac平台。除了提供C/C++接口外,也有其他语言的移植版。
    因为基于Chromium,所以CEF支持Webkit & Chrome中实现的HTML5的特性,并且在性能上面,也比较接近Chrome。

    1.从Nuget下载CEF框架

    从nuget下载是最简单的:

     我的示例程序是WPF程序,所以下载的框架是CefSharp.Wpf,你也可以下载Cef的其他版本如CefSharp.WinForms

    2.创建一个Wpf窗口:

    复制代码
    <Window x:Class="ChromeWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
            xmlns:cefSharpWPF="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
            mc:Ignorable="d"
            Title="ChromeWindow" Height="450" Width="800" Closing="Window_Closing">
        <DockPanel Name="dockpanel"  LastChildFill="True">
            <cefSharpWPF:ChromiumWebBrowser Name="mybrower" Address="https://www.cnblogs.com/tuyile006"></cefSharpWPF:ChromiumWebBrowser>
        </DockPanel>
    </Window>
    复制代码

    打开看看效果。这是超简单的使用方式,我就不展示了。

    3.让cef  chromium支持flash视频播放。

    很多网页中有flash,内嵌的chromium浏览器是不支持flash的,必须设置一下。

    需要下载一个插件,放到项目中,并随项目发布到输出目录。

     主要看构造函数中的代码:

    复制代码
    using CefSharp;
    using CefSharp.Wpf;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web;
    using System.Windows;
    namespace xiaoy.Control
    {
        /// <summary>
        /// 谷歌浏览器帮助类(静态类)  
        /// </summary>
    public class ChromeCefHelper
        {
            private static List<ChromeWindow> webList= new List<ChromeWindow>();
            private static object lockObj = new object();
    
            public static string ErrhtmlTemplate = string.Empty;
    static ChromeCefHelper()
            {
                //初始化浏览器设置
                if (!Cef.IsInitialized)
                {
                    //打开静态地址
                    string strMenu = AppDomain.CurrentDomain.BaseDirectory;
                    //pepflashplayerDLL 地址
                    string flashPath = strMenu + @"\flashPlugin\pepflashplayer64_32_0_0_414.dll";
                    CefSettings set = new CefSettings();
                    set.CachePath = strMenu + "\\cache";
                    set.PersistSessionCookies = true;
                    
                    set.LogSeverity = LogSeverity.Disable;
                    //安全证书
                    set.CefCommandLineArgs.Add("--ignore-urlfetcher-cert-requests", "1");
                    set.CefCommandLineArgs.Add("--ignore-certificate-errors", "1");
                   //开启ppapi-flash
                    set.CefCommandLineArgs["enable-system-flash"] = "1";
                    set.CefCommandLineArgs.Add("ppapi-flash-version", "32.0.0.414");                
                    //插入地址
                    set.CefCommandLineArgs.Add("ppapi-flash-path", flashPath);
    
                    //访问本地资源
                    set.RegisterScheme(new CefCustomScheme
                    {
                        SchemeName = CefSharpSchemeHandlerFactory.SchemeName,
                        SchemeHandlerFactory = new CefSharpSchemeHandlerFactory()
                    });
                   //启用配置
                    //bool bint= CefSharp.Cef.Initialize(set);
                    Cef.Initialize(set, performDependencyCheck: false, browserProcessHandler: null);
    
                    //错误网页模板
                    string htmlpath = AppDomain.CurrentDomain.BaseDirectory + "html\\error.html";
                    ErrhtmlTemplate = File.ReadAllText(htmlpath);
    
                }
            }
    
    /// <summary>
            /// 自动设置token到cookie中
            /// </summary>
            public static void SetCookies()
            {
               
                if (!string.IsNullOrEmpty(CommCach.Token))
                {
                    lock(lockObj)
                    {
                        try
                        {
                            //获取portalurl中的域名地址
                            int starti = CommCach.PortalUrl.IndexOf("//") + 2;
                            int endi = CommCach.PortalUrl.IndexOf("/", starti);
                            string domain = CommCach.PortalUrl.Substring(starti, endi - starti);
    
                            var cookieManager = CefSharp.Cef.GetGlobalCookieManager();
                            cookieManager.SetCookieAsync("http://" + domain, new CefSharp.Cookie()
                            {
                                Domain = domain,
                                Name = "Admin-Token",
                                Value = HttpUtility.UrlEncode(CommCach.Token),
                                Expires = DateTime.MinValue
                            });
                        }
                        catch(Exception ex)
                        {
                            LogHelper.Error("写Cookie失败",ex);
                        }
                    }
                    
                }
         }
    
          /// <summary>
            /// 第一次启动  
            /// </summary>
            /// <param name="url"></param>
            /// <returns></returns>
            public static ChromeWindow Open(string title,string url)
            {
                SetCookies();
                ChromeWindow cw = new ChromeWindow();
                cw.Title = title;
                cw.Open(url);
                cw.Show();
                //cw.WindowStyle = WindowStyle.None;
                webList.Add(cw); //放在缓存中  以便退出关闭浏览器
                return cw;
            }
    
            /// <summary>
            /// 在原chrome中改url
            /// </summary>
            /// <param name="webDriver"></param>
            /// <param name="url"></param>
            public static void Open(ChromeWindow webDriver, string title, string url)
            {
                if (webDriver != null)
                {
                    SetCookies();
                    webDriver.Title = title;
                    webDriver.Open(url);
                }
            }
    
            /// <summary>
            /// 关闭所有窗口
            /// </summary>
            public static void CloseAll()
            {
                foreach (ChromeWindow w in webList)
                {
                    if (w != null)
                        w.Close();               
                }
                webList.Clear();
            }
       }
    }
    复制代码
    ChromeWindow.xaml是要弹的浏览器窗体。在ChromiumWebBrowser对象初始化完之后需要支持直接打开flash播放,不能让用户点播放按钮才播放,这是用户使用习惯。实现如下:
    前端窗体可以只放个DockPanel控件,后台代码动态添加浏览器控件
    复制代码
    <Window x:Class="xiaoy.ChromeWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
            
            mc:Ignorable="d"
            Title="ChromeWindow" Height="450" Width="800" Closing="Window_Closing">
        <DockPanel Name="dockpanel"  LastChildFill="True">
            <!--<cefSharpWPF:ChromiumWebBrowser Name="mybrower" Address="https://www.cnblogs.com/tuyile006"></cefSharpWPF:ChromiumWebBrowser>-->
        </DockPanel>
    </Window>
    复制代码
     然后在Browser_IsBrowserInitializedChanged中自动播放flash
    复制代码
    using System;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using CefSharp;
    using CefSharp.Wpf;
    namespace xiaoy.Control
    {
        /// <summary>
        /// ChromeWindow.xaml 的交互逻辑
        /// </summary>
        public partial class ChromeWindow : Window
        {
            ChromiumWebBrowser browser = null;
            bool bInited = false;//是否初始化完成
            public ChromeWindow()
            {
                InitializeComponent();
                //初始化浏览器
                InitBrowser();
    
                //Open(url);
            }
    
           /// <summary>
            /// 初始化浏览器,让其支持flash
            /// </summary>
            /// <param name="url"></param>
            public void InitBrowser()
            {
                browser = new ChromiumWebBrowser();
               // browser.RequestHandler=new CustomRequestHandler();
                browser.KeyboardHandler = new CustomKeyBoardHander();
    
                BrowserSettings bset = new BrowserSettings();
                bset.Plugins = CefState.Enabled;
                bset.ApplicationCache = CefState.Enabled;
                //关于跨域限制
                //bset.WebSecurity = CefState.Disabled;
                browser.BrowserSettings = bset;
                browser.IsBrowserInitializedChanged += Browser_IsBrowserInitializedChanged;
                //打开网页
                //browser.Load(strMenu + htmlDidr);
                //绑定JS
                //browser.RegisterJsObject("callbackObj", new CallbackObjectForJs());
                
    
                // browser.FrameLoadEnd += Browser_FrameLoadEnd;
                this.dockpanel.Children.Add(browser);
            }
    
    
           private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
            {
                var visitor = new CookieVisitor(all_cookies => {
                    var sb = new StringBuilder();
                    foreach (var nameValue in all_cookies)
                        sb.AppendLine(nameValue.Item1 + " = " + nameValue.Item2);
    
                    //MessageBox.Show("读取到Cookie值:" + sb.ToString());
                    //LogHelper.Info("读取到Cookie值:" + sb.ToString());
    
                });
                Cef.GetGlobalCookieManager().VisitAllCookies(visitor);
            }
    
    private void Browser_IsBrowserInitializedChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
                try
                {
                    if ((bool)e.NewValue == true)
                    {
                        bInited = true;
                    }
    
                    if (browser.IsBrowserInitialized)
                    {
                        //自动播放flash
                        Cef.UIThreadTaskFactory.StartNew(() =>
                        {
                            string error = "";
                            var requestContext = browser.GetBrowser().GetHost().RequestContext;
                            requestContext.SetPreference("profile.default_content_setting_values.plugins", 1, out error);
                        });
    
                    }
                }
                catch(Exception ex)
                {
                    LogHelper.Error(ex);
                }
                
            }
    
           /// <summary>
            /// 打开指定网址
            /// </summary>
            /// <param name="url">网址</param>
            public void Open(string url)
            {
                //打开网页
                if (browser != null && browser.IsBrowserInitialized)
                    browser.Load(url);
                else
                    browser.Address = url;
            }
    
            private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
            {
                if (browser != null)
                {
                    browser.Dispose();
                    browser = null;
                }
            }
        }
    }
    复制代码

    4.用cef给Chromium浏览器写Cookie

    有时候需要实现免登录打开网页,即你之前已经登录过网站,打开该网站内其他网页不需要再登录。这就需要根据该网页的验证方式进行相应适配了,比如写cookie,以下就是写cookie的实现:
    复制代码
     /// <summary>
            /// 自动设置token到cookie中
            /// </summary>
            public static void SetCookies()
            {
                if (!string.IsNullOrEmpty(CommCach.Token))
                {
                    lock(lockObj)
                    {
                       try
                        {
                            //获取portalurl中的域名地址
                            int starti = CommCach.PortalUrl.IndexOf("//") + 2;
                            int endi = CommCach.PortalUrl.IndexOf("/", starti);
                            string domain = CommCach.PortalUrl.Substring(starti, endi - starti);
    
                            var cookieManager = CefSharp.Cef.GetGlobalCookieManager();
                            cookieManager.SetCookieAsync("http://" + domain, new CefSharp.Cookie()
                            {
                                Domain = domain,
                                Name = "Admin-Token",
                                Value = HttpUtility.UrlEncode(CommCach.Token),
                                Expires = DateTime.MinValue
                            });
                        }
                        catch(Exception ex)
                        {
                            LogHelper.Error("写Cookie失败",ex);
                        }
                    }
           }
    }
    复制代码

    以上是我测试的代码,请根据你自己的实际要求,修改Cookie名称和域名等。  注意SetCookieAsync的url要是http://开头。domain不要http

    5.用Cef在http请求头中加字段

    这个也是一个常见需求。以下代码实现在http头中增加access-token字段。

    增加一个ResourceRequestHandler的自定义类:

    复制代码
    using CefSharp;
    using CefSharp.Handler;
    namespace xiaoy.Control
    {
        public class CustomResourceRequestHandler :  ResourceRequestHandler
        {
          protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, 
               IRequest request, IRequestCallback callback)
            {
                var headers = request.Headers;
    
                //自动增加access-token
                if (!string.IsNullOrEmpty(CommCach.Token))
                {
                    bool bExist = false;
    
                    foreach (string k in headers.Keys)
                    {
                        if (string.Compare(k, "access-token", true) == 0)
                        {
                            bExist = true;
                            break;
                        }
                    }
                   
                    if (bExist)
                        headers["access-token"] = CommCach.Token;
                    else
                        headers.Add("access-token", CommCach.Token);
                }
               request.Headers = headers;
    
                return CefReturnValue.Continue;
            }
        }
     public class CustomRequestHandler : RequestHandler
        {
            protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, 
    IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
            {
                return new CustomResourceRequestHandler();
            }
        }
    }
    复制代码

    然后在浏览器对象创建后,增加handler

     browser = new ChromiumWebBrowser();
     browser.RequestHandler=new CustomRequestHandler();

    6.用Cef打开网页访问本地图片等资源

    如果要打开本地网页,cef支持loadhtml方法,但是浏览器权限无法打开本地资源,必须做特殊处理才可以。

    官网的方案如下:https://github.com/cefsharp/CefSharp/wiki/General-Usage#initialize-and-shutdown
    这是一个歪果仁在37.0老版本上实现的:https://thechriskent.com/tag/cefcustomscheme/
    首先实现一下ISchemeHandlerFactory接口,自定义资源解析:
    复制代码
    using CefSharp;
    using System;
    using System.IO;
    using System.Reflection;
    namespace xiaoy.Control
    {
        public class CefSharpSchemeHandlerFactory : ISchemeHandlerFactory
        {
             public const string SchemeName = "custom";
    
             public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
             {
               var fileName = request.Url.Replace(SchemeName+"://", "");
    
                Assembly ass = Assembly.GetExecutingAssembly();
                String resourcePath = ass.GetName().Name + "." + fileName.Replace("/", ".");
                Stream resource= ass.GetManifestResourceStream(resourcePath); 
    
                if (resource!=null)
                {
                    var fileExtension = Path.GetExtension(fileName);
                    return ResourceHandler.FromStream(resource,  mimeType:Cef.GetMimeType(fileExtension));
                }
    
                return null;
            }
    
        }
    }
    复制代码

    然后在初始化cef的时候(上文ChromeCefHelper中)添加

    复制代码
                    //访问本地资源
                    set.RegisterScheme(new CefCustomScheme
                    {
                        SchemeName = CefSharpSchemeHandlerFactory.SchemeName,
                        SchemeHandlerFactory = new CefSharpSchemeHandlerFactory()
                    });
                    
    
                    //启用配置
                    //bool bint= CefSharp.Cef.Initialize(set);
                    Cef.Initialize(set, performDependencyCheck: false, browserProcessHandler: null);
    复制代码

    因为你定义的schemename是“custom”,所以在你本地要打开的html中,资源地址要用“custom://”开头。

    复制代码
    <div class="content-container">
        <div class="head-line">
            <img src="custom://html/error.png" alt="" width="120"/>
        </div>
        <div class="subheader">
            {errorTitle}</div>
        <div class="hr"></div>
        <div class="context">
            <p>
                {errorContent}
            </p>
        </div>
    </div>
    复制代码

    然后可以直接调用 browser.LoadHtml方法显示本地网页了。本地网页模板建议先读取到内存中。

    复制代码
     /// <summary>
            /// 显示错误信息
            /// </summary>
            /// <param name="errTitle"></param>
            /// <param name="errContent"></param>
            public void ShowError(string errTitle,string errContent)
            {
    Task.Factory.StartNew(() => {
                    //网页中可替换的变量: {imagePath}   {errorTitle}   {errorContent}
                    //string imgpath = AppDomain.CurrentDomain.BaseDirectory + "html\\error.png";
                    //imgpath= imgpath.Replace("\\", "/");
                    string imgpath = CefSharpSchemeHandlerFactory.SchemeName+"://html/error.png";
                    //
                    string html = ChromeCefHelper.ErrhtmlTemplate.Replace("{imagePath}", imgpath).Replace("{errorTitle}", errTitle).Replace("{errorContent}", errContent);
                    //string html = string.Format(ChromeCefHelper.ErrhtmlTemplate, errTitle, errContent);
                    while (bInited == false)
                        Thread.Sleep(50);
                    browser.LoadHtml(html, CefSharpSchemeHandlerFactory.SchemeName+"://error.html");
                });
            }
    复制代码

     7.Cef中让浏览器支持F5/F12等快捷键

    内嵌的chromium浏览器是默认不支持快捷键的,需要添加keyboardhandler支持。

    复制代码
    using CefSharp;
    using System;
    using System.Windows.Forms;
    namespace xiaoy.Control
    {
       public class CustomKeyBoardHander : IKeyboardHandler
        {
    
         public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
            {
                if (type == KeyType.KeyUp && Enum.IsDefined(typeof(System.Windows.Forms.Keys), windowsKeyCode))
                {
                    var key = (Keys)windowsKeyCode;
                    switch (key)
                    {
                        case Keys.F12:
                            browser.ShowDevTools();
                            break;
                        case Keys.F5:
    
                            if (modifiers == CefEventFlags.ControlDown)
                            {
                                //MessageBox.Show("ctrl+f5");
                                browser.Reload(true); //强制忽略缓存
    
                            }
                            else
                            {
                                //MessageBox.Show("f5");
                                browser.Reload();
                            }
                            break;
                    }
                }
                return false;
            }
    
           public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode,
        int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
            {
                return false;
            }
        }
    }
    复制代码
     

    然后在浏览器对象创建后增加handler

    browser = new ChromiumWebBrowser();
    // browser.RequestHandler=new CustomRequestHandler();
    browser.KeyboardHandler = new CustomKeyBoardHander();

    转自:https://www.cnblogs.com/tuyile006/p/13852630.html

  • 相关阅读:
    December 23rd 2016 Week 52nd Friday
    December 22nd 2016 Week 52nd Thursday
    December 21st 2016 Week 52nd Wednesday
    December 20th 2016 Week 52nd Tuesday
    December 19th 2016 Week 52nd Sunday
    December 18th 2016 Week 52nd Sunday
    uva294(唯一分解定理)
    uva11624Fire!(bfs)
    fzu2150Fire Game(双起点bfs)
    poj3276Face The Right Way
  • 原文地址:https://www.cnblogs.com/javalinux/p/14283175.html
Copyright © 2011-2022 走看看