qt cef嵌入web
Posted 朝闻道
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了qt cef嵌入web相关的知识,希望对你有一定的参考价值。
原文http://blog.sina.com.cn/s/blog_9e59cf590102vnfc.html
最近项目需要,研究了下libcef库。
Cef(Chromium Embedded Framework)简述
嵌入式Chromium框架(简称CEF) 是一个由Marshall Greenblatt在2008建立的开源项目,它主要目的是开发一个基于Google Chromium的Webbrowser控件。CEF支持一系列的编程语言和操作系统,并且能很容易地整合到新的或已有的工程中去。
它的设计思想政治就是易用且兼顾性能。CEF基本的框架包含C/C++程序接口,通过本地库的接口来实现,而这个库则会隔离宿主程序和Chromium&Webkit的操作细节。它在浏览器控件和宿主程序之间提供紧密的整合,它支持用户插件,协议,javascript对象以及javascript扩展,宿主程序可以随意地控件资源下载,导航和打印等,并且可以跟Google Chrome浏览器一起,支持高性能和html5 技术。
Cef使用
首先下载cef库的源码,源码有2个大的版本,cef1和cef3,我使用的是cef3,因此cef1我就不过多解释,其实我也不太了解。刚开始使用的时候一定不能怕,可能有些人看了源码之后会发现源码异常的复杂,这个时候我建议网上多差点儿资料,因为我学的时候也是在网上找到了不少好的文章。
下边是我在编译cef库的时候遇到的一些问题:
-
因为我的项目是基于qt的来做的,而qt的运行时库是MDd类型的,因此cef3编译的时候也应该遵循这个运行时库的编译方式
-
我在网上也看到了不少介绍创建cef项目的办法,不过个人觉得好多都是只讲过程,不讲原理,其实使用这个库很简单,我直- 说debug模式,release照搬。首先拷贝exe执行所需资源文件和运行时库(Resources目录下的除include文件夹、Debug目录下所有动态库),然后拷贝连接器的静态库(out/Debug/lib目录下的静态库、Debug目录下的所有静态库)
-
根据个人使用工具的不同自行包含头文化和静态库,我使用的是vs2013,工程属性->配置属性->VC++目录,添加包含目录和库目录,在工程属性->配置属性->连接器->输入,页面附加依赖项添加依赖动态库
以上这3项基本就满足了创建包含cef项目的所有注意事项,如果自己想定制更好使用的控件,则需要相应的代码级别操作,接下来,我就讲讲代码级别基本的操作,复杂的操作我现在也了解不多。
-
注释:关于libCef库中每个类的作用,我就不多说了,自己网上随便一搜索一大堆,在这里我直说几个重要的,在我的项目里使用到的:
- CefDownloadHandler:下载回调类,当web页面上有文件下载的时候,会调用该类中的相应接口。注意一点,cef库默认是禁止了文件下载,如果想要响应这一事件,需要在OnBeforeDownload重写接口中加入代码:callback->Continue(suggested_name, true);
- CefClient:获取注册回调类
- CefDisplayHandler:地址、标题等改变调用接口,重写此类可以处理导航相关事件
- CefRenderProcessHandler:渲染进程,当浏览器创建的时候,该类中的接口会被调用,因此可是在该类的接口中注册方法或者对象到web。包含webkit初始化、导航、上下文创建等回调接口
-
CefBrowserProcessHandler:浏览器进程,上下文初始化、渲染进程创建等回调接口
cef库嵌入已有工程步骤:
1、首先需要自己集成QWidget,重写一个web窗口,如图1所示;
2、main.cpp函数添加如图2所示方法,main方法中初始化Cef库,代码如下,退出时调用CefQuit();
int result = CefInit(argc, argv);
if (result >= 0)
{
return result;
}
CefLoadPlugins(IsWow64());
3、QCefWebView,重写ClientApp::RenderDelegate的方法OnContextCreated,完成对象和方法的注册,代码如图3,图中CefMapV8handler是js在调用该接口时的回调类,该类继承自CefV8Handler,我们只需要重写该类中的Execute接口,然后根据参数name来获取js调用的是qt的哪个接口,如图4所示。
4、最后也是最终的部分,我贴上cef库初始化和我自己封装的类文件源代码,当然了,有很大一部分代码也是从网上找的
相关代码如下
cefclient.h如下:
// Initialize CEF.
int CefInit(int &argc, char **argv);
// Load web plugins.
void CefLoadPlugins(bool isWow64);
// Quit CEF.
void CefQuit();
// Quit CEF until all browser windows have closed.
void CefQuitUntilAllBrowserClosed();
// Returns the application working directory.
QString AppGetWorkingDirectory();
// Notify all browser windows have closed.
void NotifyAllBrowserClosed();
cefclient.cpp如下
namespace {
// Initialize the CEF settings.
void CefInitSettings(CefSettings& settings)
{
// Make browser process message loop run in a separate thread.
settings.multi_threaded_message_loop = true;
// Store cache data will on disk.
std::string cache_path = QString2StdStr(AppGetWorkingDirectory()) + "/.cache";
CefString(&settings.cache_path) = CefString(cache_path);
// Completely disable logging.
settings.log_severity = LOGSEVERITY_DISABLE;
// The resources(cef.pak and/or devtools_resources.pak) directory.
CefString(&settings.resources_dir_path) = CefString();
// The locales directory.
CefString(&settings.locales_dir_path) = CefString();
// Enable remote debugging on the specified port.
settings.remote_debugging_port = 8088;
// Ignore errors related to invalid SSL certificates.
//settings.ignore_certificate_errors = true;
}
} // namespace
CefRefPtr g_handler;
CefRefPtr g_appHandler;
int CefInit(int &argc, char **argv)
{
qDebug() << __FUNCTION__;
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
CefMainArgs main_args(hInstance);
g_appHandler = new ClientApp;
CefRefPtr app(g_appHandler);
// Execute the secondary process, if any.
int exit_code = CefExecuteProcess(main_args, app.get(), NULL);
if (exit_code >= 0)
return exit_code;
CefSettings settings;
CefInitSettings(settings);
#ifndef SUB_PROCESS_DISABLED
// Specify the path for the sub-process executable.
CefString(&settings.browser_subprocess_path).FromASCII("cefclient_process.exe");
#endif
settings.single_process = true;
settings.no_sandbox = true;
settings.multi_threaded_message_loop = true;
// Initialize CEF.
CefInitialize(main_args, settings, app.get(), NULL);
g_handler = new ClientHandler();
return -1;
}
void CefLoadPlugins(bool isWow64)
{
CefString flash_plugin_dir = isWow64 ? "C:\\\\Windows\\\\SysWOW64\\\\Macromed\\\\Flash"
: "C:\\\\Windows\\\\System32\\\\Macromed\\\\Flash";
CefAddWebPluginDirectory(flash_plugin_dir);
CefRefreshWebPlugins();
}
void CefQuit()
{
qDebug() << __FUNCTION__;
// Shut down CEF.
CefShutdown();
}
qcefwebview.h如下:
class QCefWebView : public QWidget
, public ClientHandler::Listener
, public ClientApp::RenderDelegate
{
Q_OBJECT
public:
enum BrowserState
{
kNone,
kCreating,
kCreated,
};
static const QString kUrlBlank;
QCefWebView(QWidget* parent = 0);
virtual ~QCefWebView();
void load(const QUrl& url);
void setHtml(const QString& html, const QUrl& baseUrl = QUrl());
QUrl url() const;
public slots:
void back();
void forward();
void reload();
void stop();
QVariant evaluateJavaScript(const QString& scriptSource);//执行js脚本
signals:
void titleChanged(QString title);
void urlChanged(QUrl url);
void loadStarted();
void loadFinished(bool ok);
void webRequest(const QString & title);
void navStateChanged(bool canGoBack, bool canGoForward);
void jsMessage(QString name, QVariantList args);
protected:
virtual void resizeEvent(QResizeEvent*);
virtual void closeEvent(QCloseEvent*);
virtual void showEvent(QShowEvent*);
virtual void customEvent(QEvent*);
//ClientHandler::Listener
virtual void OnAddressChange(const QString& url);