Android Service with Qt Remote Objects

Demonstrates how to run an Android service in a separate process, and how to communicate between the service process and the main process using Qt Remote Objects.

This example demonstrates how to create and run an Android service in a separate process from the main application process, and then exchange data between QML/C++ and the Java service using Qt Remote Objects .

When clicking the Send to Service button, the name entered in the QML view, Qt, in this case, is sent to the Android service. Then, the service replies back with a message Hello Qt which is printed in the QML view.

运行范例

要运行范例从 Qt Creator ,打开 欢迎 模式,然后选择范例从 范例 。更多信息,拜访 构建和运行范例 .

Create the Service

To start a service in its own process, extend the QtService class for your service. Extending QtService allows the service to load the necessary Qt libraries used for Qt, like Qt Remote Objects libraries.

Start by creating the Java service class. The following class extends QtService and acts as your service entry point:

package org.qtproject.example.qtandroidservice;
import android.content.Context;
import android.content.Intent;
import org.qtproject.qt5.android.bindings.QtService;
import android.util.Log;
public class QtAndroidService extends QtService {
    private static final String TAG = "QtAndroidService";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Creating Service");
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "Destroying Service");
    }
}
					

This class can have any logic you want using Java code. However, you don't need any logic to communicate with Qt as that will be done using Qt Remote Objects.

Manage the AndroidManifest.xml File

To use the service, it must be declared in the AndroidManifest.xml file as follows:

    <service android:process=":qt_service" android:name=".QtAndroidService">
            <meta-data android:name="android.app.lib_name" android:value="service"/>
            <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
            <meta-data android:name="android.app.repository" android:value="default"/>
            <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
            <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
            <!-- Deploy Qt libs as part of package -->
            <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
            <!-- Run with local libs -->
            <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
            <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
            <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
            <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
            <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
            <!-- Run with local libs -->
            <!-- Background running -->
            <meta-data android:name="android.app.background_running" android:value="true"/>
            <!-- Background running -->
        </service>
					

The important part of this service declaration is the lib_name part. It will ensure that the service is run by the service's own lib file:

            <meta-data android:name="android.app.lib_name" android:value="service"/>
					
					

Handle the Application Start

To start the service, call the following function from the application's main() :

void startService()
{
    QAndroidIntent serviceIntent(QtAndroid::androidActivity().object(),
                                        "org/qtproject/example/qtandroidservice/QtAndroidService");
    QAndroidJniObject result = QtAndroid::androidActivity().callObjectMethod(
        "startService",
        "(Landroid/content/Intent;)Landroid/content/ComponentName;",
        serviceIntent.handle().object());
}
					
					

Handle the Service Start

QAndroidService is used to create the service process. For the service to start from its own .so lib file, create a sub-project with the following .pro 文件:

TEMPLATE = lib
TARGET = service
CONFIG += dll
					
					

Communication with Qt Remote Objects

要使用 Qt Remote Objects , define a .rep 文件:

class QtAndroidService {
    SLOT(void sendToService(const QString &name));
    SIGNAL(messageFromService(const QString &message));
}
					

定义 .rep source file in the service project .pro :

REPC_SOURCE += ../common/qtandroidservice.rep
					

And in the application's .pro 文件:

REPC_REPLICA += ../common/qtandroidservice.rep
					

Then define the class used by Qt Remote Objects, which has a sendToService() slot and a messageFromService() signal:

#include "rep_qtandroidservice_source.h"
class QtAndroidService : public QtAndroidServiceSource
{
public slots:
    void sendToService(const QString &name) override {
        emit messageFromService("Hello " + name);
    };
};
					

Include the class in the previous snippet in main.cpp :

#include "rep_qtandroidservice_replica.h"
					

Now, in the service's service_main.cpp , create the QRemoteObjectHost node and start QAndroidService :

#include "qtandroidservice_ro.h"
#include <QDebug>
#include <QAndroidService>
int main(int argc, char *argv[])
{
    qWarning() << "QtAndroidService starting from separate .so";
    QAndroidService app(argc, argv);
    QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")));
    QtAndroidService qtAndroidService;
    srcNode.enableRemoting(&qtAndroidService);
    return app.exec();
}
					

In the application's main.cpp , create the client node and connect it to the source node created in the service and connect it to the QML view:

    QRemoteObjectNode repNode;
    repNode.connectToNode(QUrl(QStringLiteral("local:replica")));
    QSharedPointer<QtAndroidServiceReplica> rep(repNode.acquire<QtAndroidServiceReplica>());
    engine.rootContext()->setContextProperty("qtAndroidService", rep.data());
    bool res = rep->waitForSource();
    Q_ASSERT(res);
    rep->sendToService("Qt");
					

Then, add a Connections element to watch for the incoming messages from the service:

    Connections {
        target: qtAndroidService
        function onMessageFromService(message) {
            pongText.text = message
        }
    }
					

And set the onClicked for the sending button to:

        onClicked: qtAndroidService.sendToService(pingText.text)
					

范例工程 @ code.qt.io

另请参阅 Android Service with Qt Remote Objects - Same Lib File , Android 服务 , Qt for Android ,和 Qt Android Extras .