一、QtWebengineView使用要点:
向项目中添加相应模块:QT += webenginewidgets
QWebChannel实现与网页Javascript交互:
- QWebChannel *channel = new QWebChannel(this);
- channel->registerObject("bridge", (QObject*)bridge::instance());
- m_webview->page()->setWebChannel(channel);
网上有很多使用的例子,这里不做赘述,这里主要是针对QtWebengineView加载网页过程分析。
二、QtWebengineView加载网页
void QWebEngineView::load(const QUrl& url)
{
page()->load(url);
}
这里page:
QWebEnginePage* QWebEngineView::page() const
{
Q_D(const QWebEngineView);
if (!d->page) {
QWebEngineView *that = const_cast<QWebEngineView*>(this);
that->setPage(new QWebEnginePage(that));
}
return d->page;
}
由此可知实际上调用的是QWebEnginePage的load函数。接着进入到QWebEnginePage中:
void QWebEnginePage::load(const QUrl& url)
{
Q_D(QWebEnginePage);
d->adapter->load(url);
}
而adapter这里代码如下:
QSharedPointer<QtWebEngineCore::WebContentsAdapter> adapter;
顺着WebContentsAdapter继续找:
void WebContentsAdapter::load(const QUrl &url)
{
QWebEngineHttpRequest request(url);
load(request);
}
void WebContentsAdapter::load(const QWebEngineHttpRequest &request)
{
Q_D(WebContentsAdapter);
GURL gurl = toGurl(request.url());
if (!isInitialized()) {
//注意这里:这里就是生成一个访问实例
scoped_refptr<content::SiteInstance> site =
content::SiteInstance::CreateForURL(d->browserContextAdapter->browserContext(), gurl);
initialize(site.get());
}
CHECK_VALID_RENDER_WIDGET_HOST_VIEW(d->webContents->GetRenderViewHost());
// The situation can occur when relying on the editingFinished signal in QML to set the url
// of the WebView.
// When enter is pressed, onEditingFinished fires and the url of the webview is set, which
// calls into this and focuses the webview, taking the focus from the TextField/TextInput,
// which in turn leads to editingFinished firing again. This scenario would cause a crash
// down the line when unwinding as the first RenderWidgetHostViewQtDelegateQuick instance is
// a dangling pointer by that time.
if (LoadRecursionGuard::isGuarded(this))
return;
LoadRecursionGuard guard(this);
Q_UNUSED(guard);
// Add URL scheme if missing from view-source URL.
if (request.url().scheme() == content::kViewSourceScheme) {
QUrl pageUrl = QUrl(request.url().toString().remove(0,
strlen(content::kViewSourceScheme) + 1));
if (pageUrl.scheme().isEmpty()) {
QUrl extendedUrl = QUrl::fromUserInput(pageUrl.toString());
extendedUrl = QUrl(QString("%1:%2").arg(content::kViewSourceScheme,
extendedUrl.toString()));
gurl = toGurl(extendedUrl);
}
}
//这个对象是请求的具体内容:包括请求方式、内容
content::NavigationController::LoadURLParams params(gurl);
params.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
switch (request.method()) {
case QWebEngineHttpRequest::Get:
params.load_type = content::NavigationController::LOAD_TYPE_DEFAULT;
break;
case QWebEngineHttpRequest::Post:
params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
// chromium accepts LOAD_TYPE_HTTP_POST only for the HTTP and HTTPS protocols
if (!params.url.SchemeIsHTTPOrHTTPS()) {
d->adapterClient->loadFinished(false, request.url(), false,
net::ERR_DISALLOWED_URL_SCHEME,
QCoreApplication::translate("WebContentsAdapter",
"HTTP-POST data can only be sent over HTTP(S) protocol"));
return;
}
break;
}
params.post_data = network::ResourceRequestBody::CreateFromBytes(
(const char*)request.postData().constData(),
request.postData().length());
// convert the custom headers into the format that chromium expects
QVector<QByteArray> headers = request.headers();
for (QVector<QByteArray>::const_iterator it = headers.cbegin(); it != headers.cend(); ++it) {
if (params.extra_headers.length() > 0)
params.extra_headers += '\n';
params.extra_headers += (*it).toStdString() + ": " + request.header(*it).toStdString();
}
bool resizeNeeded = false;
if (request.url().hasFragment()) {
if (content::RenderWidgetHostView *rwhv = webContents()->GetRenderWidgetHostView()) {
const gfx::Size &viewportSize = rwhv->GetVisibleViewportSize();
resizeNeeded = (viewportSize.width() == 0 || viewportSize.height() == 0);
}
}
auto navigate = [this, params]() {
Q_D(WebContentsAdapter);
//发出请求
webContents()->GetController().LoadURLWithParams(params);
// Follow chrome::Navigate and invalidate the URL immediately.
d->webContentsDelegate->NavigationStateChanged(webContents(), content::INVALIDATE_TYPE_URL);
focusIfNecessary();
};
if (resizeNeeded) {
// Schedule navigation on the event loop.
QTimer::singleShot(0, navigate);
} else {
navigate();
}
}