CEF | CEF浏览器客户端功能详解

1,787 阅读5分钟

背景

VS2017+Qt5.14.2+cef89 实现基于CEF框架的客户端。上一篇文章已经介绍过如何搭建Qt+CEF开发环境,并且成功移植运行了cefsimple项目。如果不满足于cefsimple现有的功能,想开发更多的功能,比如实现浏览器的前进、后退、刷新、跳转页面时不创建新的窗口、设置cookie、调用控制台等功能。就需要深挖一下cef的控制类有哪些,支持的功能接口有哪些……

cefsimple示例详解

文件目录

image.png

这里的文件目录是直接生成的cef.sln打开后的文件目录。移植到Qt项目中时,主要用到了simple_app.cc、simple_app.h、simple_handler.cc、simple_handler.h、simple_handler_win.cc文件和cefsimple_win.cc文件中的wWinMain函数中的内容。


具体实现

1.main函数

1657850918168.jpg

main函数主要用来在程序启动时对CEF进行初始化设置和启动,并在程序结束时关闭CEF。

  • CefEnableHighDPISupport(): 在进程启动时设置High-DPI为启用状态。DPI全称是dots per inch (DPI), 也就是每英寸的点数,在显示器上就是每英寸的像素个数。这个接口函数在使用时一般不为人所注意,但是如果稍有不慎,会造成打开的网页不能填满窗口的问题。
  • GetModuleHandle(nullptr): GetModuleHandle是一个计算机函数,功能是获取一个应用程序或动态链接库的模块句柄。只有在当前进程的场景中,这个句柄才会有效。其实就是获取示例的句柄。
  • CefMainArgs: 表示CefExecuteProcess参数的类。
  • CefRefPtr<CefApp> app(new SimpleApp): CEF创建对象形式如CefRefPtr<SimpleApp> app(new SimpleApp);或者CefRefPtr<SimpleApp> app = new SimpleApp();创建的指针引用计数由CefRefPtr管理,CefRefPtr通过调用AddRef()和Release()方法自动管理引用计数。
  • CefExecuteProcess(): 这个函数应该在应用程序入口点进行调用来执行二级进程。它可以从一个可执行的浏览器客户端或从一个单独的执行的指定的CefSettings来开启二级进程。即CefExecuteProcess生成一个功CEF浏览器运行的线程。保证browser的独立运行。注意这里创建失败的话,就直接退出程序。
  • CefSettings: 是一个包含浏览器相关设置的结构体。

no_sandbox: 沙盒是在受限的安全环境中运行应用程序的一种做法,这种做法是要限制授予应用程序的代码访问权限。沙盒中的所有改动对操作系统不会造成任何损失。设置为ture以禁止子进程的沙盒。
multi_threaded_message_loop: 设置多线程消息循环。设置为false时,可以调用CefRunMessageLoop或者CefDoMessageLoopWork函数来触发Cef消息循环,这时浏览器进程的UI线程就是调用CefRunMessageLoop或者CefDoMessageLoopWork函数的线程。当为true时,CEF将在单独的线程上运行Browser的界面,而不是在主线程上。 一般默认为false,通过使用定时器进行事件触发CefDoMessageLoopWork来进行事件处理。(仅在windows上支持此选项)

  • CefInitialize(): 初始化CEF。
  • CefRunMessageLoop(): 因为上面我们将multi_threaded_message_loop设置为false,所以需要调用CefRunMessageLoop()函数来出发CEF的消息循环。结束消息循环调用CefQuitMessageLoop()。
  • CefShutdown(): 关闭CEF。

至此,CEF完成了SimpleApp的创建以及CEF的初始化、启动、开启消息循环、关闭等工作。我自在使用过程中加了一些东西,大家在开发过程中可以作为参考,不懂的地方建议直接点进去看cef的注释,讲的很清楚。

int main(int argc, char *argv[])
{
    // Create CEF
    CefEnableHighDPISupport();
    HINSTANCE hInstance = GetModuleHandle(nullptr);
    CefMainArgs main_args(hInstance);
    CefRefPtr<ClientApp> app(new ClientApp);
    int exit_code = CefExecuteProcess(main_args, app.get(), nullptr);
    if (exit_code >= 0) {
        return exit_code;
    }

    // 主程序
    QApplication a(argc, argv);

    // Init CEF
    CefSettings settings;
    settings.no_sandbox = true;
    settings.multi_threaded_message_loop = true;
    settings.persist_session_cookies = true;
    CefString(&settings.cache_path).FromString(storagePath.toStdString());
    CefString(&settings.root_cache_path).FromString(storagePath.toStdString());
    CefString(&settings.locale).FromString("zh-CN");                // 浏览器语言设置为中文
    CefString(&settings.accept_language_list).FromString("zh-CN");  // 浏览器语言设置为中文
    CefInitialize(main_args, settings, app.get(), nullptr);
    
    // 运行主程序
    int ret = a.exec();
    
    // Shut down CEF.
    CefShutdown();
    return ret;
}
2.SimpleHandler类

image.png

SimpleHandler类继承了CefClient、CefDisplayHandler、CefLifeSpanHandler、CefLoadHandler这几个类。并重载了这些类中的部分方法。这些handler的都是基于功能的回调类,应用开发者应该提供对应的实现,然后提供应用程序获取对应的handler实体。

  • CefClient: 提供了一些获取Handler的方法。
  • CefDisplayHandler: 回调类,用来处理与页面状态相关的事件,如页面加载情况的变化,地址栏变化,标题变化等。
  • CefLifeSpanHandler: 回调类,主要用来处理与浏览器生命周期相关的事件,和浏览器对象的创建、销毁以及弹出框的管理。
  • CefLoadHandler: 回调类,主要用来处理浏览器页面加载状态的变化,如页面加载开始,完成,出错等。

另:如果我们需要浏览器响应按键消息,还可以继承CefKeyboardHandler类。

  • CefKeyboardHandler: 回调类,主要用来处理键盘输入事件。
3.SimpleApp类

image.png

SimpleApp类继承了CefApp、CefBrowserProcessHandler这两个类。并重载了这两类中的部分方法。\

  • CefApp 是一个接口类,主要用于提供获取三种handler的接口。GetResourceBundleHandler、 GetBrowserProcessHandler、GetRenderProcessHandler这三个方法分别可以得到对应的回调handler。同时如果继承了这三种handler就可以在这些时机处理自己的回调业务。就像后面继承的CefBrowserProcessHandler,可以实现browser进程的回调,用于执行browser进程生命周期中的重要回调。
  • CefBrowserProcessHandler 实现对浏览器进程的回调。在OnContextInitialized回调函数中进行应用程序参数初始化和窗口创建。

cefsimple中的OnContextInitialized()回调函数内容较复杂,很多我们都用不到。简化后的函数可以是: image.png

  • 创建SimpleHandler。
  • CefBrowserSettings: 是一个结构体,里面保存了对浏览器的一些设置,包括设置标准字体、语言、默认编码等信息。
  • url: 是将要访问的网页的网址。
  • CefWindowInfo: 是表示窗口信息的类。可以设置浏览器窗口以何种方式显示出来以及窗口的大小。有三种显示方式:SetAsChild、SetAsPopup和SetAsWindowless。
  • SetAsPopup: 创建一个弹出窗口的浏览器。
  • SetAsChild: 将浏览器创建为子窗口。后续我们实现将浏览器嵌入QWidget就是用这个方式来实现。
  • SetAsWindowless: 创建没有窗口的浏览器。所有实现将通过CefRenderHandler接口来操作。一般浏览器都是用作可视化显示的,这个方式一般不使用。

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿