您现在的位置是:网站首页> C/C++

Qt使用miniblink

  • C/C++
  • 2022-11-28
  • 1173人已阅读
摘要

Qt使用miniblink

## 一、前言

用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最新版内核,去除了chromium所有多余的部件,只保留最基本的排版引擎blink。miniblink保持了10M左右的极简大小,是所有同类产品最小的体积,同时支持windows


qt+miniblink用法步骤:


- 第一步:调用wkeSetWkeDllPath函数加载dll文件路径,一个项目只需要执行一次。


- 第二步:调用wkeInitialize初始化动态库,一个项目只需要执行一次。


- 第三步:调用wkeCreateWebWindow创建一个浏览器控件,传入句柄。


- 第四步:调用wkeOnLoadingFinish注册回调加载完成信号,有需要才注册。


- 第五步:调用wkeJsBindFunction注册回调接收数据的方法,一定要放在这里在网页加载前执行。


- 第六步:调用wkeLoadURL加载网址、wkeLoadFile加载网页文件、wkeLoadHtmlWithBaseUrl加载网页内容。


- 第七步:调用wkeRunJS执行js函数,超级简单。


- 第八步:调用wkeFinalize释放资源,只要执行一次,在整个项目结束的时候。


qt+miniblink完整demo开源地址:


https://gitee.com/feiyangqingyun/QWidgetDemo/tree/master/miniblink


https://github.com/feiyangqingyun/QWidgetDemo/tree/master/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

#include "miniblink.h"

#include "qapplication.h"

#include "qdebug.h"


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 file = qApp->applicationDirPath() + "/miniblink_64.dll";

#else

        QString file = qApp->applicationDirPath() + "/miniblink.dll";

#endif

        const wchar_t *path = reinterpret_cast<const wchar_t *>(file.utf16());

        wkeSetWkeDllPath(path);

        bool ok = wkeInitialize();

        qDebug() << QString("init miniblink %1").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)

{

    const char *temp = url.toLocal8Bit().data();

    if (file) {

        wkeLoadFile(webView, temp);

    } else {

        wkeLoadURL(webView, temp);

    }

}


void miniblink::setHtml(const QString &html, const QString &baseUrl)

{

    wkeLoadHtmlWithBaseUrl(webView, html.toLocal8Bit().data(), baseUrl.toLocal8Bit().data());

}


void miniblink::runJs(const QString &js)

{

    wkeRunJS(webView, js.toLocal8Bit().data());

}


C++调用JavaScript

和wke一样,wkexe也可以通过相同的wkeRunJS函数调用JavaScript代码,但不同的是,如果C++代码想要获得JavaScript的返回值,需要在调用的JS代码前加上return:


jsRet = wkeRunJS(gWkeWebView, "return funcforcplusplus(\"\xe4\xbd\xa0\xe5\xa5\xbd ABCDEFG\")");

jsRetStr = jsToStringW(wkeGlobalExec(gWkeWebView), jsRet);

MessageBox(hWnd, jsRetStr, L"runJS返回", 0);


JavaScript调用C++

同wke一样,JS调用C++代码也需要绑定,在RunApplication函数中CreateWebWindow之前添加如下代码:


jsBindFunction("msgBox", js_msgBox, 2);//JS调用C++

1

同时在app.cpp文件中添加:


//JS调用C++

jsValue JS_CALL js_msgBox(jsExecState es)

{

    const wchar_t* text = jsToStringW(es, jsArg(es, 0));

    const wchar_t* title = jsToStringW(es, jsArg(es, 1));

    MessageBox(NULL, text, title, 0);

    return jsStringW(es, L"C++返回字符串");


}

这里有个BUG需要注意,miniblink的jsToStringW函数目前只能处理JavaScript传入的字符串参数(作者将在下步更新代码时修正),如果前端msgBox函数传入的参数不是字符串类型,那么会得到空值

附上前端测试用的HTML代码如下:


<!DOCTYPE html>

<html xmlns="/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>WKE Test Web Page</title>

<script>

function funcforcplusplus(instr){

    document.getElementById('result').value=instr;

    return navigator.userAgent;

    //return "JavaScript Return 返回啦";

}

</script>

</head>

<body>

<p>WKE Test Web Page</p>

<a href='#' onclick="document.getElementById('result').value=msgBox('TEST Function from JS to Cpp','来自Javascript的调用');">LINK</a>

<textarea rows='6' cols='36' id='result'>hello</textarea>

</body>

</html>


Top