0

I'm using the QT 5.9 WebEngine framework to display web pages. I'm injecting javascript into a page when it loads, and want to allow the javascript to be able to access a QT object.

I get the QWebchannel callback in JS to be invoked but the object method and properties are undefined.

NOTE: I NEED to inject all JS code and cannot change the html code of the loaded page. Meaning i cannot include any js script nor write any js code directly in the html pages.

Here is my code:

I create the QWebEnginePage object with a profile and inject the JS files as below:

// file: webview.cpp, webview extends **QWebEngineView**

QWebEngineScript script;
script.setSourceCode(qwebchannelsource); // source is qwebchannel.js
script.setInjectionPoint(QWebEngineScript::DocumentCreation);
profile->scripts()->insert(script);
QWebEnginePage page* = new QWebEnginePage(profile, this);

QWebChannel *channel = new QWebChannel(page);
page->setWebChannel(channel);
channel->registerObject(QStringLiteral("jshelper"), &JSHelper::instance());

JSHelper

class JSHelper : public QObject
{
public:
    static JSHelper &instance();
    QString someString;
    int someInt;

    Q_INVOKABLE int getInt();
    Q_PROPERTY(int myIntInCppSide READ getInt)

private:
    JSHelper();
};

JS code

// also injected into the page (like qwebchannel.js) at QWebEngineScript::DocumentReady

new QWebChannel(qt.webChannelTransport, function (channel) {
    var jshelper = channel.objects.jshelper;
    console.warn('qwebchannel triggered');

    // do what you gotta do
    if (jshelper === undefined) {
        console.warn("jshelper is undefined");
    }
    else {
        console.warn("jshelper is awesome");
    }

    console.warn("jshelper value of string " + jshelper.somestring);
    console.warn("jshelper value of int " + jshelper.myIntInCppSide);
    jshelper.myIntInCppSide(function (n) {
        console.warn("jshelper value of int " + n);
    });
});

my output:

qwebchannel triggered"
jshelper is awesome"
jshelper value of string undefined"
jshelper value of int undefined"
Uncaught TypeError: jshelper.myIntInCppSide is not a function"

As you can see I have tried various suggestions from several answers but nothing seems to fix my issue that the function does not exist. Even when using the remote debugging I can see the jshelper is of type QObject but it does not have the properties nor methods of my class.

QT QWebEnginePage::setWebChannel() transport object

Undefined properties and return types when using QWebChannel

Anand
  • 4,182
  • 6
  • 42
  • 54
  • Have you tried to insert `Q_OBJECT` macro in the beginning of `JSHelpre` class declaration? – Dmitry Aug 10 '17 at 19:42
  • yes, I get 'undefined reference to vtable for JSHelper' compile error – Anand Aug 11 '17 at 08:30
  • Ah, I missed the fact that you have the default constructor private, that must be the reason for the compilation error. Can you check what happens if you make the default constructor public and use the `Q_OBJECT` macro? – Dmitry Aug 11 '17 at 08:33
  • THANKS! I broke my head for 2 days and got no info about setting the Q_OBJECT macro anywhere. Making the class constructor public and adding the macro fixed my problem – Anand Aug 11 '17 at 08:44
  • Glad it helped. Posted this as the answer, would you mind accepting it? ) – Dmitry Aug 11 '17 at 08:54

1 Answers1

0

JSHelper class misses Q_OBJECT macro. As the official documentation says,

Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the Meta Object Compiler on the source file. We strongly recommend the use of this macro in all subclasses of QObject regardless of whether or not they actually use signals, slots and properties, since failure to do so may lead certain functions to exhibit strange behavior.

Also the constructor of this class needs to be made public for Qt's introspection facilities to be able to work with the class.

Dmitry
  • 3,063
  • 2
  • 22
  • 32