简体   繁体   English

如何将QT5 QML插件部署到Android?

[英]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中发现了一些丑陋的地方:

  1. 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。

  2. 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。

  3. 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:”前缀加载。

  4. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM