Search code examples
javavisual-c++java-native-interfaceqt5.4

Qt can't find platform plugins when loaded by JNI


So this is a variant of the "failed to load platform plugin" issue with the Qt platform abstraction. I have a C++ Library which depends on the Qt Framework. Everything works when I create a C++ Application and call the library with the Qt Dependencies in the project folder.

But I want to use the C++ project with Java. JNI is able to load the dependent Qt Libraries but the platform plugin seems to get loaded by Qt itself and there somewhere lies the problem: The platform plugin isn't loaded. I get the standard "This application failed to start because it could not find or load the Qt platform plugin X" error.

I am guessing that it is a path issue. No matter where I put the plugins, Qt can't find them. I'd expect it to work, if i put all native Libraries in the java project folder and the plugin under javaProject/platforms, but it doesn't work. Putting it under the java project folder itself or adding both /platforms and it's root folder to the path variable yielded no result. I also tried to load the plugin explicitly in Java, but it didn't work. I am running out of ideas.

Static Linking is sadly not an option because the C++ Library also depends on plugins.

EDIT: Stumbled over the Qt 4.8 deployment doc: The Plugin Directory When the application is run, Qt will first treat the application's executable directory as the pluginsbase. For example if the application is in C:\Program Files\MyApp and has a style plugin, Qt will look in C:\Program Files\MyApp\styles. (See QCoreApplication::applicationDirPath() for how to find out where the application's executable is.) Qt will also look in the directory specified by QLibraryInfo::location(QLibraryInfo::PluginsPath), which typically is located in QTDIR/plugins (where QTDIR is the directory where Qt is installed). If you want Qt to look in additional places you can add as many paths as you need with calls to QCoreApplication::addLibraryPath(). And if you want to set your own path or paths you can use QCoreApplication::setLibraryPaths(). You can also use a qt.conf file to override the hard-coded paths that are compiled into the Qt library. For more information, see the Using qt.conf documentation. Yet another possibility is to set the QT_PLUGIN_PATH environment variable before running the application. If set, Qt will look for plugins in the paths (separated by the system path separator) specified in the variable.

Setting the QT_PLUGIN_PATH variable didn't have any effect, I assume it is deprecated. The solution to the puzzle might be the path QCoreApplication::applicationDirPath() is pointing, when loaded by jni.


Solution

  • One solution would be to place your DLL/shared Qt C++ library under an accessible directory and add that directory name to Qt's library path:

    QApplication::addLibraryPath(<full path of your directory name>);
    

    For example, I have a Qt for Android application which calls my Qt C++ library "libMyQtCppLib.so" via JNI. I place it under "/tmp/qt5/plugins":

    /tmp/qt5/plugins/libMyQtCppLib.so

    And in my Qt main() function, I call:

    QApplication::addLibraryPath(QLatin1String("/tmp/qt5/plugins"));
    

    This works for me when my application is run on Android. I have not tried this solution on Windows. But you could give it a try to see how it works on your platform.