添加条件判断后QWebChannel实现JS调用C++功能失败
问题原因分析
核心问题是栈对象生命周期和异步逻辑不匹配,具体有两个错误点:
- 你将
QWebChannel channel、JsInterface jsInterface两个核心对象定义为if代码块内的栈变量,if块执行完成后,这两个对象会立即被栈内存回收。而QWebEngineView::loadFinished是异步信号,需要等网页加载完成后才会触发,触发时channel和jsInterface已经被销毁,你调用setWebChannel传入的指针成为野指针,通信链路直接失效。 - 你在lambda捕获中用了
[&browser]捕获指针的引用,browser本身是if块内的栈变量,if块结束后browser指针变量本身被销毁,lambda执行时访问的是野引用,也会导致逻辑异常。
修复方案
你可以任选以下任意一种方案修复:
方案1:提升变量作用域
将channel、jsInterface、browser的定义移到if块之外,保证对象生命周期覆盖异步信号的触发时机:
bool testwebchannel_main = true; // 变量定义移到块外 QWebEngineView * browser = nullptr; QWebChannel * channel = nullptr; JsInterface * jsInterface = nullptr; if ( testwebchannel_main ) { browser = new QWebEngineView; browser->resize(QSize(800,600)); browser->show(); browser->load(QUrl("http://www.wikipedia.org")); channel = new QWebChannel; jsInterface = new JsInterface; browser->page()->setWebChannel(channel, 42); channel->registerObject(QString("JsInterface"), jsInterface); // 捕获改为值捕获,直接存指针地址 QObject::connect(browser, &QWebEngineView::loadFinished, [browser](bool ok) { qDebug()<<"Load Finished " << ok; // TEST CODE HERE QString code = QStringLiteral( R"DELIM( var links = document.getElementsByTagName('a'); for ( var i=0; i<links.length; ++i) { links[i].style.backgroundColor = 'yellow'; }; )DELIM"); browser->page()->runJavaScript(code, 42); browser->page()->runJavaScript(qWebChannelJs(), 42); QString code2 = QStringLiteral( R"DELIM( window.webChannel = new QWebChannel(qt.webChannelTransport, function( channel) { var cpp = channel.objects.JsInterface; cpp.log("Hello from JavaScript"); }); )DELIM"); browser->page()->runJavaScript(code2, 42); }); }
方案2:绑定对象生命周期到QWebEngineView
利用Qt的父子内存管理机制,将channel和jsInterface的父对象设为browser,browser销毁时会自动回收子对象,同时捕获改为值捕获:
bool testwebchannel_main = true; if ( testwebchannel_main ) { QWebEngineView * browser = new QWebEngineView; browser->resize(QSize(800,600)); browser->show(); browser->load(QUrl("http://www.wikipedia.org")); // 动态分配,设置父对象为browser QWebChannel * channel = new QWebChannel(browser); JsInterface * jsInterface = new JsInterface(browser); browser->page()->setWebChannel(channel, 42); channel->registerObject(QString("JsInterface"), jsInterface); // 值捕获browser指针 QObject::connect(browser, &QWebEngineView::loadFinished, [browser](bool ok) { qDebug()<<"Load Finished " << ok; // 原有逻辑不变 QString code = QStringLiteral( R"DELIM( var links = document.getElementsByTagName('a'); for ( var i=0; i<links.length; ++i) { links[i].style.backgroundColor = 'yellow'; }; )DELIM"); browser->page()->runJavaScript(code, 42); browser->page()->runJavaScript(qWebChannelJs(), 42); QString code2 = QStringLiteral( R"DELIM( window.webChannel = new QWebChannel(qt.webChannelTransport, function( channel) { var cpp = channel.objects.JsInterface; cpp.log("Hello from JavaScript"); }); )DELIM"); browser->page()->runJavaScript(code2, 42); }); }
内容的提问来源于stack exchange,提问作者blzt
相关产品推荐
相关产品推荐

