[英]How to deploy qt5 qml plugin to android?
I am trying to import TimeExample Qt Quick Extension Plugin from Qt 5.1.0 android installation. 我正在尝试从Qt 5.1.0 android安装导入TimeExample Qt快速扩展插件。
libqmlqtimeexampleplugin.so
is built sucessfully in build-plugins-Android_for_arm_GCC_4_6_Qt_5_1_0-Debug/imports
libqmlqtimeexampleplugin.so
已在build-plugins-Android_for_arm_GCC_4_6_Qt_5_1_0-Debug/imports
成功build-plugins-Android_for_arm_GCC_4_6_Qt_5_1_0-Debug/imports
Then I created simple Qt Quick2 Application (built-in Elements) from Qt Creator. 然后,我从Qt Creator创建了简单的Qt Quick2应用程序(内置元素)。 What should I add to application project file to get QML plugin in output ".apk" package?
我应该添加什么到应用程序项目文件中以在输出“ .apk”包中获取QML插件?
Now it says: 现在它说:
W/Qt (23528): assets:/qml/TimeExampleTest/main.qml:2 (): assets:/qml/TimeExampleTest/main.qml:2:1: module "TimeExample" is not installed
W / Qt(23528):资产:/qml/TimeExampleTest/main.qml:2():资产:/qml/TimeExampleTest/main.qml:2:1:未安装模块“ TimeExample”
main.qml main.qml
import QtQuick 2.0
import TimeExample 1.0 // import types from the plugin
Rectangle {
width: 360
height: 360
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
Time { // this class is defined in C++ (plugin.cpp)
id: time
}
hours: time.hour
minutes: time.minute
}
}
TimeExampleTest.pro TimeExampleTest.pro
folder_01.source = qml/TimeExampleTest
folder_01.target = qml
folder_02.source = /home/artem/Projects/Veedo/Test/build-plugins-Android_for_arm_GCC_4_6_Qt_5_1_0-Debug/imports/TimeExample
folder_02.target = imports
DEPLOYMENTFOLDERS = folder_01 folder_02
QML_IMPORT_PATH = /home/artem/Projects/Veedo/Test/build-plugins-Android_for_arm_GCC_4_6_Qt_5_1_0-Debug/imports/TimeExample
SOURCES += main.cpp
include(qtquick2applicationviewer/qtquick2applicationviewer.pri)
qtcAddDeployment()
OTHER_FILES += \
android/src/org/kde/necessitas/ministro/IMinistro.aidl \
android/src/org/kde/necessitas/ministro/IMinistroCallback.aidl \
android/src/org/qtproject/qt5/android/bindings/QtActivity.java \
android/src/org/qtproject/qt5/android/bindings/QtApplication.java \
android/AndroidManifest.xml \
android/version.xml \
android/res/values-ja/strings.xml \
android/res/values-rs/strings.xml \
android/res/values-zh-rTW/strings.xml \
android/res/values-fa/strings.xml \
android/res/values-ru/strings.xml \
android/res/values-fr/strings.xml \
android/res/values-ro/strings.xml \
android/res/values-el/strings.xml \
android/res/values-ms/strings.xml \
android/res/values-nb/strings.xml \
android/res/values-et/strings.xml \
android/res/values-pl/strings.xml \
android/res/values-pt-rBR/strings.xml \
android/res/values-es/strings.xml \
android/res/values-id/strings.xml \
android/res/values-de/strings.xml \
android/res/values-it/strings.xml \
android/res/values-zh-rCN/strings.xml \
android/res/values/strings.xml \
android/res/values/libs.xml \
android/res/layout/splash.xml \
android/res/values-nl/strings.xml
With Qt 5.3, we managed to get our QML plugin recognized by a Qt Android app only by deploying the plugin to the QT_INSTALL_QML directory where official Qt QML modules reside. 使用Qt 5.3,我们仅通过将插件部署到官方Qt QML模块所在的QT_INSTALL_QML目录中,就设法使我们的QML插件被Qt Android应用程序识别。 This directory is /opt/Qt/5.3/android_armv7/qml in our case.
在我们的情况下,该目录为/opt/Qt/5.3/android_armv7/qml。
Plugin Side 插件侧
Our .pro
file for the plugin looks like: 我们的插件
.pro
文件如下所示:
TEMPLATE = lib
TARGET = prova
QT += qml quick multimedia
CONFIG += qt plugin c++11 console
CONFIG -= android_install
TARGET = $$qtLibraryTarget($$TARGET)
uri = com.mycompany.qmlcomponents
# Input
SOURCES += \
src1.cpp \
src2.cpp
HEADERS += \
src1.h \
src2.h
##The below is generated automatically by Qt Creator when you create a new "Qt Quick 2 Extension Plugin" project for Android
#Copies the qmldir file to the build directory
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
copy_qmldir.target = $$OUT_PWD/qmldir
copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
copy_qmldir.commands = $(COPY_FILE) \"$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)\"
QMAKE_EXTRA_TARGETS += copy_qmldir
PRE_TARGETDEPS += $$copy_qmldir.target
}
#Copies the qmldir file and the built plugin .so to the QT_INSTALL_QML directory
qmldir.files = qmldir
unix {
installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir
}
Our qmldir
(in the plugin source tree root) file is: 我们的
qmldir
(在插件源树根目录中)文件是:
module com.mycompany.qmlcomponents
plugin prova
Application Side 应用方
The .pro file looks like: .pro文件如下所示:
TEMPLATE = app
QT += qml quick widgets multimedia
CONFIG+= console
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Default rules for deployment.
include(deployment.pri)
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
ANDROID_EXTRA_LIBS = \
/opt/Qt/5.3/android_armv7/qml/com/mycompany/qmlcomponents/libprova.so
}
We don't actually know if the inclusion of the extra libprova.so is necessary. 我们实际上并不知道是否需要包含额外的libprova.so。 It's most probably not.
可能不是。
The main.cpp
looks like: main.cpp
看起来像:
#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[]){
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
return app.exec();
}
The main.qml
just includes the plugin like: main.qml
仅包含如下插件:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtMultimedia 5.0
import com.mycompany.qmlcomponents 1.0
...
Building and Deployment 建立与部署
The way we build and deploy the plugin is to qmake
(from the android-armv7 toolchain of Qt), then make install
. 我们构建和部署插件的方法是先使用
qmake
(来自Qt的android-armv7工具链),然后make install
。 It installs the qmldir file and the plugin .so to the QT_INSTALL_QML directory. 它将qmldir文件和插件.so安装到QT_INSTALL_QML目录。
The way we build and deploy the project that uses the plugin is to qmake
(again, from the android-armv7 toolchain of Qt), then make install INSTALL_ROOT=.
我们构建和部署使用该插件的项目的方法是
qmake
(同样,来自Qt的android-armv7工具链),然后make install INSTALL_ROOT=.
(installs to build directory), then run androiddeployqt
. (安装到构建目录),然后运行
androiddeployqt
。 The last command creates the Android project structure with the qmldirs in assets/ and libraries in libs/ and bundles the whole thing in an apk via ant
. 最后一个命令创建一个Android项目结构,其资产/的qmldirs和libs /的库,并通过
ant
将整个东西捆绑到apk中。 For the details of this procedure, refer to http://qt-project.org/wiki/Android . 有关此过程的详细信息,请参阅http://qt-project.org/wiki/Android 。
In short, we were only able to get our QML plugin recognized inside an Android project by putting it inside the private Qt qml directory. 简而言之,我们只能通过将QML插件放入私有Qt qml目录中来使其在Android项目中得到认可。
After reading Qt's source about QAbstractFileEngineHandler, I found something ugly in Qt: 在阅读了Qt关于QAbstractFileEngineHandler的资料之后,我在Qt中发现了一些丑陋的地方:
Qt does implemented some kind of mechanism to provide "searchpath" (not URL) like "qrc:", "assets:", where the kernel is QAbstractFileEngineHandler. Qt确实实现了某种机制来提供诸如“ qrc:”,“ assets:”之类的“搜索路径”(而非URL),其中内核为QAbstractFileEngineHandler。
QAbstractFileEngineHandler becomes no longer public in Qt5, it only provide abstract to QFile, QFileInfo, QDir, QIcon, and things provided by QFile, including QImage, plus QAndroidAssetsFileEngineHandler, which is specialized for Android assets. QAbstractFileEngineHandler不再在Qt5中公开,它仅提供QFile,QFileInfo,QDir,QIcon以及QFile提供的东西的摘要,包括QImage以及专门用于Android资产的QAndroidAssetsFileEngineHandler。
So SearchPath schema is not compatible with QUrl even they look so similar, as you know QtQuick is setSource to some URL, so a qml file would not loaded by "assets:" prefix directly. 因此,SearchPath模式与QUrl不兼容,即使它们看起来如此相似,您也知道QtQuick已将setSource设置为某个URL,因此qml文件不会直接由“ assets:”前缀加载。
You can find this below [static] void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
in Qt's document: 您可以在Qt的文档中的
[static] void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
下面找到[static] void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
:
QDir::setSearchPaths("icons", QStringList(QDir::homePath() + "/images")); QDir::setSearchPaths("docs", QStringList(":/embeddedDocuments")); ... QPixmap pixmap("icons:undo.png"); // will look for undo.png in QDir::homePath() + "/images" QFile file("docs:design.odf"); // will look in the :/embeddedDocuments resource path
You will find this snippet not work because QPixmap did not load image from QAbstractFileEngineHandler, may this be Qt's undocumented changes. 您会发现此代码段无效,因为QPixmap并未从QAbstractFileEngineHandler加载图像,这可能是Qt的未记录更改。 On the other hand, QtCore unit test about searchpath only tested on QFile
另一方面,关于searchpath的QtCore单元测试仅在QFile上进行了测试
Further more, void addResourceSearchPath(const QString &path)
is obsoleted, however setSearchPath is defective, I feel pretty confused on this. 此外,
void addResourceSearchPath(const QString &path)
已过时,但是setSearchPath有缺陷,对此我感到很困惑。 Maybe I should take a look in QUrl now :) 也许我现在应该看看QUrl :)
Here is how I got this done. 这是我完成这项工作的方式。
Add this to your application code: 将此添加到您的应用程序代码:
QQuickView *m_view;
m_view->engine()->addImportPath("assets:/");
m_view->engine()->addPluginPath(QCoreApplication::applicationDirPath());
Forward slash after "assets:" is important, it won't work without it. “资产:”之后的正斜杠很重要,没有它就无法工作。 In your build folder you need to have directory structure like this:
/home/my_name/project_build_directory/qml/my_plugin
. 在您的构建文件夹中,您需要具有以下目录结构:
/home/my_name/project_build_directory/qml/my_plugin
。 Your plugin directory should have your .so
library and the qmldir
file. 您的插件目录应具有
.so
库和qmldir
文件。 Then you need to get the plugin packaged. 然后,您需要将插件打包。 This should be possible by adding the following to your
.pro
file: 通过将以下内容添加到您的
.pro
文件中,应该可以实现:
ANDROID_EXTRA_PLUGINS += /full/path/to/your/plugin/folder
This however didn't work for me with Qt Creator from Qt 5.11 so what I had to do was to add this manually to the .json
deployment file : 但是对于Qt 5.11的Qt Creator,这对我不起作用,所以我要做的就是手动将此添加到
.json
部署文件中:
"android-extra-plugins":"/full/path/to/your/plugin",
The build variable might work in earlier versions of the Qt Creator. build变量可能在早期版本的Qt Creator中起作用。 If your plugins have Qt dependencies they will not be picked up by androiddeployqt, you will have to add them manually.
如果您的插件具有Qt依赖项,则androiddeployqt不会选择它们,您必须手动添加它们。 This is done by either adding a build variable to the .pro file:
这可以通过向.pro文件添加构建变量来完成:
ANDROID_EXTRA_LIBS += /your/qt/path/lib/libQt5Xml.so
... etc
or if that doesn't work, you'll have to add this manually to the JSON build file: 否则,您将不得不手动将其添加到JSON构建文件中:
"android-extra-libs":"/your/qt/path/lib/libQt5Xml.so,/your/qt/path/lib/libQt5Network.so",
...etc
The process is messy, the JSON file is automatically regenerated on some changes to the build so the changes will have to be pasted to it again. 该过程很混乱,在对构建进行某些更改时会自动重新生成JSON文件,因此必须将更改再次粘贴到该文件。 If anyone knows how to improve the process this would be appreciated.
如果有人知道如何改进流程,将不胜感激。 What you should end up with on your android device is, your plugin
.so
will end up in the same directory all .so
libraries are in and your qmldir
will end up in assets:/your_plugin_name/qmldir
. 您应该在Android设备上最终看到的是,您的插件
.so
将最终位于所有.so
库所在的同一目录中,而您的qmldir
最终将在assets:/your_plugin_name/qmldir
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.