最近领导想在 Qt 的交易客户端上嵌入 web 页面
有的做成 QWindow 可以独立打开关闭,有的做成 QWidget 可以添加到 QTabWidget 里
Qt 想使用 Web 的话,可以选择 QWebEngine、CEF、WebView2
领导用的是 mac 上用 parallels desktop 虚拟出来的 Windows 11,性能很差
测试下来,发现 QWebEngine 稍卡、cef 很流畅、WebView2 最流畅
用 https://web.basemark.com/ 跑的分
QtWebEngine 使用的 6.8.3 vs2022 x64 release
cef 用的 https://github.com/CefView/QCefView
写了一些 demo,包括 C++ 和 JS 通信的,反正最后没用上,就不提了
最终是用了微软的 WebVIew2
优点是性能和原生的 chrome 几乎没差别(-5%左右),打包变小了(减少了200M左右)
缺点是不能跨平台,只能在 windows 上用
接下来重点说下 WebView2
https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/?form=MA13LH#download
https://github.com/MicrosoftEdge/WebView2Samples.git
https://www.nuget.org/packages/Microsoft.Web.WebView2
https://www.nuget.org/packages/Microsoft.Windows.ImplementationLibrary
进入网页后点击右侧的下载按钮,来下载下面两个支持包
下载后发现是.nupkg文件,右键用 7-zip 解压
webview.h
x
using namespace Microsoft::WRL;
class WebView : public QWidget
{
Q_OBJECT
public:
explicit WebView(QWidget* parent = nullptr, QString url = QString());
~WebView();
void sendJson(QString str);
private:
wil::com_ptr<ICoreWebView2Controller> webviewController;
wil::com_ptr<ICoreWebView2> webview;
wil::com_ptr<ICoreWebView2Settings> settings;
QString m_url;
void initializeWebView2();
void resizeEvent(QResizeEvent* event);
};
webview.cpp
xxxxxxxxxx
WebView::WebView(QWidget* parent, QString url)
: QWidget(parent), m_url(url)
{
initializeWebView2();
}
WebView::~WebView()
{
if (webviewController) {
webviewController = nullptr;
}
if (webview) {
webview = nullptr;
}
}
void WebView::sendJson(QString str)
{
webview->PostWebMessageAsJson(str.toStdWString().c_str());
}
void WebView::initializeWebView2()
{
HWND hwnd = (HWND)this->winId();
// WebView2 用户数据存储路径
LPCWSTR userDataFolder = L"C:\\ProgramData\\Cache";
// 允许加载本地 html 和 js
std::wstring args;
args.append(L"--disable-web-security");
auto options = Microsoft::WRL::Make<CoreWebView2EnvironmentOptions>();
options->put_AdditionalBrowserArguments(args.c_str());
CreateCoreWebView2EnvironmentWithOptions(nullptr, userDataFolder, options.Get(),
Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>([this, hwnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {
if (FAILED(result)) {
qDebug() << "WebView2 环境创建失败: " << result;
return result;
}
env->CreateCoreWebView2Controller(hwnd, Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
[this, hwnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
if (FAILED(result) || !controller) {
qDebug() << "WebView2 控制器创建失败: " << result;
return result;
}
webviewController = controller;
webviewController->get_CoreWebView2(&webview);
// 禁用 F12 调试
webview->get_Settings(&settings);
settings->put_AreDevToolsEnabled(false);
// 设置创建的框体的大小
RECT bounds;
GetClientRect(hwnd, &bounds);
webviewController->put_Bounds(bounds);
std::wstring htmlPath = m_url.toStdWString();
webview->Navigate(htmlPath.c_str());
return S_OK;
}).Get());
return S_OK;
}).Get());
}
void WebView::resizeEvent(QResizeEvent* event)
{
if (webviewController) {
RECT bounds;
GetClientRect((HWND)this->winId(), &bounds);
webviewController->put_Bounds(bounds);
}
QWidget::resizeEvent(event);
}
动态库库引入
WebView2Loader.dll.lib
头文件引入
WebView2.h
WebView2EnvironmentOptions.h
wil 目录
使用方式
WebView *view = new WebView(this, “http://www.baidu.com”);
Qt 集成 https://blog.csdn.net/Baizn/article/details/145581641
Qt 集成 https://blog.csdn.net/andybegin/article/details/134120854
JS 调用 https://learn.microsoft.com/zh-cn/microsoft-edge/webview2/how-to/communicate-btwn-web-native