7

Is it possible to load QML plugin from C++, say, from QPluginLoader to work with it's functions? In my project, I have a qml plugin with a version information in it and I want to read it from C++.

Example:

main() {
    // ...
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml")));

    if (parser.isSet(verionsOption)) {
        QSharedPointer<QQmlExtensionPlugin> myPlugin = // load plugin
        std::cout << "Version of plugin: " << myPlugin->version() << std::endl;
    }

    return app.exec();
}
1
  • Sure you can do it. Dont't you read it from C++ in your example? Commented Jan 23, 2015 at 15:32

1 Answer 1

6

The anwser is.. yes. After few months I was able to get to this task back again.

So, in the qt source code we can see what QQmlExtensionPlugin. It is really a qt plugin (which we are able to open through QPluginLoader) - QPlugin. In my opinion it should be listed in Qt's plugin type list.

To be able to open your qml plugin in the application your plugin class must implement some interface to which you will cast with qobject_cast in the application. In my project it looks like:

#ifndef MYPLUGIN_H
#define MYPLUGIN_H

#include <QQmlExtensionPlugin>

class ExternalInterface
{
public:
    virtual const QString pluginVersion() const = 0;
    virtual const QString qxmppVersion() const = 0;
    virtual ~ExternalInterface() {}
};

Q_DECLARE_INTERFACE(ExternalInterface, "com.my.ExternalInterface")

class MyPlugin : public QQmlExtensionPlugin, public ExternalInterface
{
    Q_OBJECT
    Q_INTERFACES(ExternalInterface)
    Q_PLUGIN_METADATA(IID "com.MyPlugin")

    public:
        void registerTypes(const char *uri);
        void initializeEngine(QQmlEngine *engine, const char *uri);

        const QString pluginVersion() const final override;
        const QString qxmppVersion() const final override;
};

#endif // MYPLUGIN_H

Next, in main.cpp of the application which opens the plugin:

ExternalInterface* pluginVersion = nullptr;
#ifdef Q_OS_MACOS
    const QString fileSuffix = ".dylib";
#else
    const QString fileSuffix = ".so";
#endif
    QPluginLoader qmlPlugin(QApplication::applicationDirPath() + "../PlugIns/quick/libmyplugin" + fileSuffix);
    qmlPlugin.load();
    if (qmlPlugin.isLoaded()) {
        pluginVersion = qobject_cast<ExternalInterface*>(qmlPlugin.instance());
    } else {
            qmlPlugin.setFileName(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath) + "/fx/my/libmyplugin" + fileSuffix);
        qmlPlugin.unload();
        qmlPlugin.load();
        if (qmlPlugin.isLoaded()) {
            pluginVersion = qobject_cast<ExternalInterface*>(qmlPlugin.instance());
        } else {
            qDebug() << "ERROR while opening plugin: " << qmlPlugin.errorString();
        }
    }

    if (pluginVersion) {
        qDebug() << "Plugin: \n" << pluginVersion->pluginVersion() << "\n"
                 << pluginVersion->qxmppVersion() << "\n"
                 << "Location: " << qmlPlugin.fileName();
    } else {
        qDebug() << "Can't obtain version information from the plugin";
    }

The worst thing here is that you must provide full path to the plugin (shared library) and you need to know where it installs on different systems.

Sign up to request clarification or add additional context in comments.

1 Comment

it is awesome and so helpful. I used this for unit test as a subproject.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.