文章目录
- 一、前言
- 二、miniblink简介
- 三、miniblink使用
- 四、运行效果
- 五、工程结构
一、前言
本文取自刘典武大师:Qt编写地图综合应用58-兼容多浏览器内核
用Qt做项目过程中,遇到需要用到浏览器控件的项目,可能都会绕不开一个问题,那就是从Qt5.6版本开始mingw编译器的Qt构建套件,不再提供浏览器控件了,之前还可以用webkit
控件,这下很多项目要么选择5.6以下版本,要么选择msvc的构建套件,而且大部分的msvc构建套件还不自带浏览器控件,也需要自己编译,只有原配的构建套件比如Qt5.9+VS2015、Qt5.12+VS2017这种搭配才可能有浏览器控件,不然就算你勾选了浏览器控件也不会安装,这样就使得很多依赖浏览器控件的项目比较被动。
于是必须寻找一个轻量级的浏览器控件来替代,比如cef
、miniblink
,个人更倾向于miniblink
,用法极其简单,依赖极其精简就一个dll
,在linux
和mac
系统上本来qt
就一直会有浏览器控件,所以也就不涉及到跨平台的问题,所以miniblink
暂支持windows
的缺点也就不算缺点了。
二、miniblink简介
屌炸天的内核来袭,史上最小chromium内核miniblink!
miniblink github
miniblink
是一个追求极致小巧的浏览器内核项目,全世界第三大流行的浏览器内核控件。其基于chromium
最新版内核,去除了chromium
所有多余的部件,只保留最基本的排版引擎blink
。miniblink
保持了10M左右的极简大小,是所有同类产品最小的体积,同时支持windows xp
、npapi
。
qt+miniblink用法步骤:
- 第一步:调用
wkeSetWkeDllPath
函数加载dll文件路径,一个项目只需要执行一次。 - 第二步:调用
wkeInitialize
初始化动态库,一个项目只需要执行一次。 - 第三步:调用
wkeCreateWebWindow
创建一个浏览器控件,传入句柄。 - 第四步:调用
wkeOnLoadingFinish
注册回调加载完成信号,有需要才注册。 - 第五步:调用
wkeJsBindFunction
注册回调接收数据的方法,一定要放在这里在网页加载前执行。 - 第六步:调用
wkeLoadURL
加载网址、wkeLoadFile
加载网页文件、wkeLoadHtmlWithBaseUrl
加载网页内容。 - 第七步:调用
wkeRunJS
执行js
函数,超级简单。 - 第八步:调用
wkeFinalize
释放资源,只要执行一次,在整个项目结束的时候。
三、miniblink使用
使用miniblink
需要三个文件:wke.h
、miniblink.dll
、miniblink_64.dll
刘典武大师封装了一个miniblink
浏览器类
#ifndef MINIBLINK_H
#define MINIBLINK_H
#include <QWidget>
#include "wke.h"
class miniblink : public QWidget
{
Q_OBJECT
public:
explicit miniblink(QWidget *parent = 0);
//初始化资源
static void init();
//释放资源
static void release();
protected:
//设置浏览器控件自动适应大小
void resizeEvent(QResizeEvent *);
private:
//浏览器控件对象
wkeWebView webView;
signals:
//网页载入完成
void loadFinished(bool ok);
//收到网页发出来的数据
void receiveDataFromJs(const QString &type, const QVariant &data);
public:
//给回调用的函数
void loadFinish(bool ok);
void receiveData(const QString &type, const QVariant &data);
public slots:
//加载网址或者本地文件
void load(const QString &url, bool file = false);
//加载html内容
void setHtml(const QString &html, const QString &baseUrl);
//执行js函数
void runJs(const QString &js);
};
#endif // MINIBLINK_H
#pragma execution_character_set("utf-8")
#include "miniblink.h"
#include "qapplication.h"
#include "qmessagebox.h"
#include "qdatetime.h"
#include "qfile.h"
#include "qvariant.h"
#include "qdebug.h"
#define TIMEMS QTime::currentTime().toString("hh:mm:ss zzz")
void onLoadingFinish(wkeWebView, void *param, const wkeString, wkeLoadingResult result, const wkeString)
{
//qDebug() << "onLoadingFinish" << result;
//在注册函数的地方就已经传入了类指针
miniblink *widget = (miniblink *)param;
//0 = WKE_LOADING_SUCCEEDED, 1 = WKE_LOADING_FAILED, 2 = WKE_LOADING_CANCELED
widget->loadFinish(result == 0);
}
jsValue WKE_CALL_TYPE objName_receiveData(jsExecState es, void *param)
{
if (0 == jsArgCount(es)) {
return jsUndefined();
}
//挨个取出参数,设定的通用方法,只有两个参数
jsValue arg0 = jsArg(es, 0);
jsValue arg1 = jsArg(es, 1);
if (!jsIsString(arg0)) {
return jsUndefined();
}
//在注册函数的地方就已经传入了类指针
miniblink *widget = (miniblink *)param;
QString type = QString::fromStdString(jsToString(es, arg0));
QVariant data = QString::fromStdString(jsToString(es, arg1));
widget->receiveData(type, data);
return jsUndefined();
}
miniblink::miniblink(QWidget *parent) : QWidget(parent)
{
//第一步先初始化动态库
init();
//第二步初始化浏览器控件
//创建一个浏览器控件,放入句柄
webView = wkeCreateWebWindow(WKE_WINDOW_TYPE_CONTROL, (HWND)this->winId(), 0, 0, this->width(), this->height());
//关联完成信号
wkeOnLoadingFinish(webView, onLoadingFinish, this);
//设置浏览器控件可见
wkeShowWindow(webView, TRUE);
//注册通用的接收数据的方法,一定要放在这里在网页加载前执行
wkeJsBindFunction("objName_receiveData", objName_receiveData, this, 2);
}
void miniblink::init()
{
//全局只需要初始化一次
static bool isInit = false;
if (!isInit) {
isInit = true;
//不同的构建套件位数加载不同的动态库
#ifdef Q_OS_WIN64
QString flag = "64";
QString file = qApp->applicationDirPath() + "/miniblink_64.dll";
#else
QString flag = "32";
QString file = qApp->applicationDirPath() + "/miniblink.dll";
#endif
//如果文件不存在则提示
if (!QFile(file).exists()) {
QMessageBox::critical(0, "错误", file + "\n文件不存在请先拷贝!");
return;
}
const wchar_t *path = reinterpret_cast<const wchar_t *>(file.utf16());
wkeSetWkeDllPath(path);
bool ok = wkeInitialize();
qDebug() << TIMEMS << QString("init miniblink_%1 %2").arg(flag).arg(ok ? "ok" : "error");
}
}
void miniblink::release()
{
wkeFinalize();
}
void miniblink::resizeEvent(QResizeEvent *)
{
wkeResize(webView, this->width(), this->height());
}
void miniblink::loadFinish(bool ok)
{
emit loadFinished(ok);
}
void miniblink::receiveData(const QString &type, const QVariant &data)
{
emit receiveDataFromJs(type, data);
}
void miniblink::load(const QString &url, bool file)
{
QByteArray data = url.toUtf8();
const char *temp = data.data();
if (file) {
wkeLoadFile(webView, temp);
} else {
wkeLoadURL(webView, temp);
}
}
void miniblink::setHtml(const QString &html, const QString &baseUrl)
{
QByteArray dataHtml = html.toUtf8();
QByteArray dataUrl = baseUrl.toUtf8();
wkeLoadHtmlWithBaseUrl(webView, dataHtml.data(), dataUrl.data());
}
void miniblink::runJs(const QString &js)
{
QByteArray data = js.toUtf8();
wkeRunJS(webView, data.data());
}
有了这个浏览器类之后,就可以正常的调用接口了
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "miniblink.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
miniblink *webView;
private slots:
void initForm();
//网页载入完成
void loadFinished(bool ok);
//收到网页发出来的数据
void receiveDataFromJs(const QString &type, const QVariant &data);
private slots:
void on_btnLoadUrl_clicked();
void on_btnLoadFile_clicked();
void on_btnLoadHtml_clicked();
void on_btnRunJs_clicked();
void on_horizontalSlider_valueChanged(int value);
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include "qapplication.h"
#include "qdebug.h"
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
this->initForm();
on_btnLoadFile_clicked();
}
Widget::~Widget()
{
delete ui;
}
void Widget::initForm()
{
webView = new miniblink;
connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
connect(webView, SIGNAL(receiveDataFromJs(QString, QVariant)),
this, SLOT(receiveDataFromJs(QString, QVariant)));
ui->gridLayout->addWidget(webView, 0, 0);
}
void Widget::loadFinished(bool ok)
{
qDebug() << "加载完成" << ok;
}
void Widget::receiveDataFromJs(const QString &type, const QVariant &data)
{
qDebug() << "收到数据" << type << data;
}
void Widget::on_btnLoadUrl_clicked()
{
webView->load("https://www.baidu.com");
}
void Widget::on_btnLoadFile_clicked()
{
webView->load(qApp->applicationDirPath() + "/demo.html", true);
}
void Widget::on_btnLoadHtml_clicked()
{
QStringList html;
html << "<html><body>";
html << "<h2>Hello World</h2>";
html << "</body></html>";
webView->setHtml(html.join(""), "");
}
void Widget::on_btnRunJs_clicked()
{
webView->load(qApp->applicationDirPath() + "/gauge.html", true);
}
void Widget::on_horizontalSlider_valueChanged(int value)
{
QString js = QString("setGaugeValue(%1)").arg(value);
webView->runJs(js);
}
四、运行效果
需要把
miniblink.dll
、miniblink_64.dll
放到可执行文件目录下,才能运行起来