Транспортный объект QT QWebEnginePage::setWebChannel()

Я использую фреймворк QT WebEngine для отображения веб-страниц. Я ввожу javascript в страницу, когда она загружается, и хочу, чтобы javascript мог получить доступ к объекту QT. По-видимому, для этого должен существовать QWebChannel, который устанавливает некоторый IPC между хромом (javascript) и остальной частью моего проекта C++/QT. Я наткнулся на функцию QWebEnginePage::setWebChannel (QWebChannel *channel), однако не могу найти примеров ее использования. Документация (http://doc.qt.io/qt-5/qwebenginepage.html#setWebChannel) упоминает, что qt.webChannelTransport должен быть доступен в контексте javascript, но я не вижу, где это установлено в qwebchannel.js (https://github.com/qtproject/qtwebchannel/blob/dev/src/webchannel/qwebchannel.js). Я видел примеры WebChannel (http://doc.qt.io/qt-5/qtwebchannel-examples.html) и хотел бы по возможности избегать использования веб-сокетов.

Ниже показано, как я пытался реализовать веб-канал.

Каждый раз, когда загружается страница, я устанавливаю канал и вставляю javascript на C++:

QWebChannel *channel = new QWebChannel();
channel->registerObject(QStringLiteral("jshelper"), helper);

view->page()->runJavaScript(qwebjs); //this is qwebchannel.js
view->page()->setWebChannel(channel);
view->page()->runJavaScript(myfunction); //function that calls QT object (jshelper)

В Javascript:

new QWebChannel(qt.webChannelTransport, function(channel) { ... });

Это приводит к тому, что канал не подключается должным образом (при условии, что это из-за qt.webChannelTransport, поскольку он работал, когда я использовал WebSockets). Любые указатели на примеры настройки QWebChannel с помощью QWebEnginePage также приветствуются.


person mathieujofis    schedule 10.08.2015    source источник


Ответы (1)


Короткий ответ: добавьте <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> на свою html-страницу (конечно, перед вызовом new QWebChannel) и удалите строку view->page()->runJavaScript(qwebjs); //this is qwebchannel.js из кода C++.

Длинный ответ:

У меня тоже была куча проблем с выяснением того, как правильно использовать QWebChannel без WebSockets - мне удалось заставить его работать после копания в исходном коде Qt 5.5 и списках рассылки (документация все еще отсутствует). Обратите внимание, что это работает только с новой версией Qt 5.5. .

Вот как использовать QWebChannel:

// file: MyWebEngineView.cpp, MyWebEngineView extends QWebEngineView
QWebChannel *channel = new QWebChannel(page());

// set the web channel to be used by the page
// see http://doc.qt.io/qt-5/qwebenginepage.html#setWebChannel
page()->setWebChannel(channel);

// register QObjects to be exposed to JavaScript
channel->registerObject(QStringLiteral("jshelper"), helper);

// now you can call page()->runJavaScript(...) etc
// you DON'T need to call runJavaScript with qwebchannel.js, see the html file below

// load your page
load(url);

И на стороне JS:

<!-- NOTE: this is what you're missing -->
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>

<script type="text/javascript">
    <!-- it's a good idea to initialize webchannel after DOM ready, if your code is going to manipulate the DOM -->
    document.addEventListener("DOMContentLoaded", function () {
        new QWebChannel(qt.webChannelTransport, function (channel) {
            var jshelper = channel.objects.jshelper;
            // do what you gotta do
        });
    });
</script>

Также убедитесь, что вы добавили QT += webenginewidgets webchannel в свой файл .pro, иначе он не будет собран!

Бонус: теперь вы можете отлаживать свой JavaScript, не выходя из Chrome Dev Tools! Просто добавьте это где-нибудь в свой код Qt (в идеале при запуске вашего приложения):

#ifdef QT_DEBUG
    qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "23654");
#endif

Затем запустите приложение, перейдите к http://localhost:23654 в Chrome, и вы получите полнофункциональный отладчик JS, профилировщик, консоль и т. д. :)


Последующие действия (19 апреля 2016 г.): если ваш удаленный отладчик не работает, обратите внимание, что вызов qputenv также должен выполняться до любых вызовов QWebEngineSettings или любых других класс, связанный с WebEngine, потому что они немедленно запускают процесс «зиготы» WebEngine (зигота — это родительский процесс QtWebEngineProcess, из которого разветвляются все будущие процессы QtWebEngineProcess), а затем qputenv не могут повлиять на него. Потратил несколько часов на отслеживание этого.

person Vicky Chijwani    schedule 12.08.2015
comment
Это здорово - моя единственная проблема в том, что я должен вводить скрипты, так как у меня нет никакого контроля над загружаемыми страницами. Кроме того, когда вы говорите о новом QT 5.5, вы имеете в виду ветку разработчиков? Я использую QT Creator 5.5.0, и я не уверен, насколько обновлен исходный код QT, с которым я работаю. Я попробовал настройку переменной среды для отладки JS в консоли, но она не работает (я думаю, потому что этот параметр отладки взят из недавней фиксации). - person mathieujofis; 13.08.2015
comment
Я понимаю. В Qt Creator перейдите в Инструменты > Параметры > Сборка и запуск > Версии Qt и проверьте, какая у вас версия. Когда я говорю Qt 5.5, я имею в виду стабильную версию который был выпущен 1 июля этого года. В Qt 5.5 добавлена ​​встроенная поддержка Chromium IPC через QWebChannel (т. е. QWebEnginePage::setWebChannel() и qt.webChannelTransport в JS). Кроме того, ваш Qt Creator не может быть версии 5.5, последняя версия v3.4.2 :) - person Vicky Chijwani; 13.08.2015
comment
Кроме того, QTWEBENGINE_REMOTE_DEBUGGING присутствует в выпуске Qt 5.5: stackoverflow.com/a/29721197/504611 - person Vicky Chijwani; 13.08.2015
comment
В конце концов это удалось — удаленная отладка действительно помогла. По большей части это был правильный ответ, за исключением того, что в моей ситуации я ввел qwebchannel.js, который работает хорошо. - person mathieujofis; 02.11.2015
comment
примечание: в деструкторе, если у хелпера есть родительский хелпер dergister; page()-›webChannel()-›deregisterObject(helper); - person khani_mahdi; 26.01.2016
comment
У меня проблема с объектом qt, который теряется после перезагрузки страницы: js: Uncaught ReferenceError: qt is not defined. Я попытался создать новый канал и настроить его на страницу в слоте страницы загрузки, но это не работает. - person Oleh Pomazan; 13.07.2016
comment
@OlehPomazan да, я испытал то же самое: веб-канал плохо работает с перезагрузкой страницы. Возможно, они исправят это в более поздней версии. - person Vicky Chijwani; 13.07.2016
comment
@VickyChijwani Большое спасибо за краткий ответ! У меня была точная проблема с передачей объектов JS на C++ в Qt 5.7.0. Теперь это работает как шарм. Спасибо еще раз! - person Manmohan Singh; 10.08.2016
comment
@mathieujofis, есть ли шанс, что вы можете опубликовать код, который сработал для вас? потому что, кроме части внедрения кода, ваш код и код Вики довольно идентичны, и мне тоже нужно ввести как qwebchannel.js, так и другой код JS. В настоящее время я получаю обратный вызов в JS, и объект jshelper определен, но не его функции или свойства. - person Anand; 10.08.2017
comment
Возможно, стоит отметить, что QTWEBENGINE_REMOTE_DEBUGGING — это обычная переменная среды. Конечно, вы можете установить его с помощью qputenv(), но в системе POSIX вы также можете просто запустить свое приложение с терминала с помощью QTWEBENGINE_REMOTE_DEBUGGING=54321 ./myApp. Любой метод установки envvar будет работать, нет необходимости даже изменять код (если вы этого не хотите). - person FeRD; 30.08.2020