Auf dieser Seite

Android-Dienste

Mit Qt können Sie Android-Dienste erstellen. Ein Dienst ist eine Komponente, die im Hintergrund läuft und daher keine Benutzeroberfläche besitzt. Er eignet sich für lang andauernde Vorgänge wie die Aufzeichnung von GPS-Daten, das Warten auf Benachrichtigungen aus sozialen Medien und Ähnliches. Ein Dienst läuft auch dann weiter, wenn die Anwendung, die ihn gestartet hat, beendet wird.

Den Dienst zusammenstellen

Erstellen Sie zunächst ein Android-Paketverzeichnis gemäß den Anweisungen unter „Erweiterung von Qt um Android-Funktionen“. Dieses Verzeichnis enthält die Datei „ AndroidManifest.xml “. Erstellen Sie innerhalb des Paketverzeichnisses ein Verzeichnis „ src “, in dem alle Ihre Java-Pakete und -Klassen angelegt werden.

Erstellen der Service-Klasse

Bei der Entscheidung, ob Sie „ QtService “ oder „Android Service“ verwenden möchten, gelten dieselben Überlegungen wie bei „Activity “. Sofern Sie keine Funktionen nutzen, für die das Laden der Qt-Bibliotheken erforderlich ist – wie beispielsweise native Qt-Aufrufe und Ereignisbehandlung –, sollte die Erweiterung von „ Service “ funktionieren.

Sie können einen Dienst erstellen, indem Sie Ihre Java-Klasse von der Klasse ` QtService ` oder `Service` ableiten. Je nachdem, ob Sie Qt-Funktionen in Ihrem Dienst nutzen oder native C++-Funktionen aus Java aufrufen möchten, müssen Sie entweder ` QtService ` oder ` Service` vererben. Beginnen wir mit einem einfachen Dienst wie folgt:

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import org.qtproject.qt.android.bindings.QtService;

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");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        int ret = super.onStartCommand(intent, flags, startId);

        // Do some work

        return ret;
    }
}

Starten Sie den Dienst

Android ermöglicht es, Dienste bei Bedarf oder beim Systemstart zu starten. Beides ist auch mit Qt möglich.

Einen Dienst bei Bedarf starten

Sie können den Dienst auf folgende Weise starten:

  • Direkt aus C++ heraus mithilfe von ` QAndroidIntent ` und ` QJniObject`, indem Sie einen Service-Intent erstellen und die Methode `startService()` der Hauptaktivität der App aufrufen:
    // Outside of the function body
    Q_DECLARE_JNI_CLASS(Intent, "android/content/Intent")
    Q_DECLARE_JNI_CLASS(ComponentName, "android/content/ComponentName")
    Q_DECLARE_JNI_CLASS(QtAndroidService, "org/qtproject/example/qtandroidservice/QtAndroidService")
    
    // Inside function body
    using namespace QtJniTypes;
    using namespace QNativeInterface;
    
    auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>();
    Q_ASSERT(androidApp);
    Context context = androidApp->context();
    
    QJniEnvironment env;
    auto serviceClass = env.findClass(Traits<QtAndroidService>::className());
    Intent serviceIntent(context, serviceClass);
    context.callMethod<ComponentName>("startService", serviceIntent);
  • Starten Sie den Dienst durch Aufruf einer Java-Methode. Am einfachsten ist es, eine statische Methode in Ihrer Dienstklasse zu erstellen:
    public static void startQtAndroidService(Context context) {
            context.startService(new Intent(context, QtAndroidService.class));
    }

    Anschließend können Sie diese Methode von C++ aus mit dem folgenden JNI-Aufruf aufrufen:

    using namespace QtJniTypes;
    using namespace QNativeInterface;
    // ...
    auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>();
    Q_ASSERT(androidApp);
    Context context = androidApp->context();
    QtAndroidService::callStaticMethod<void>("startQtAndroidService", context);

Einen Dienst beim Systemstart starten

Um einen Dienst beim Systemstart auszuführen, benötigen Sie einen BroadcastReceiver.

Erstellen Sie eine benutzerdefinierte Java-Klasse:

public class QtBootServiceBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent startServiceIntent = new Intent(context, QtAndroidService.class);
        context.startService(startServiceIntent);
    }
}

Fügen Sie den folgenden ` uses-permission ` in den Hauptteil des Abschnitts ` <manifest> ` in der Datei ` AndroidManifest.xml ` ein:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Fügen Sie außerdem die Definition von „ receiver “ im Hauptteil des Abschnitts „ <application> “ ein:

<receiver android:name=".QtBootServiceBroadcastReceiver" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>
Einschränkungen
  • Mit Android 15.0 wurden einige Einschränkungen beim Starten von Vordergrunddiensten nach dem Empfang von BOOT_COMPLETED eingeführt. Weitere Informationen finden Sie unter Einschränkungen bei BOOT_COMPLETED.
  • Mit Android 8.0 wurden einige Einschränkungen beim Ausführen von Hintergrunddiensten eingeführt, was bedeutet, dass die Verwendung einer normalen „ Service “-Klasse möglicherweise nicht funktioniert. Weitere Informationen finden Sie in der Empfehlung von Android, entweder Vordergrunddienste oder „JobIntentService“ zu verwenden.

Verwalten des Dienstes in der Datei „AndroidManifest.xml“

Damit der Dienst in einer Android-App genutzt werden kann, müssen Sie ihn in der Datei „ AndroidManifest.xml “ deklarieren. Beginnen wir mit dem Hinzufügen des Dienstabschnitts:

  • Wenn Sie die Datei „ Service “ erweitern, deklarieren Sie den Service-Abschnitt einfach wie einen normalen Android-Dienst. Fügen Sie Folgendes innerhalb des Abschnitts „ <application> “ ein:
    <service android:name=".QtAndroidService" android:exported="true">
        <meta-data android:name="android.app.background_running" android:value="true"/>
    </service>

    Auf diese Weise wird der Dienst im selben Prozess wie ` QtActivity` gestartet, wodurch Sie native C++-Aufrufe aus Java-Code heraus nutzen können. Sie können ihn auch in einem separaten Prozess ausführen, allerdings können Sie in diesem Fall keine nativen Aufrufe für die Kommunikation verwenden, da die Qt-Bibliotheken für diesen Prozess nicht geladen sind. Um den Dienst in einem separaten Prozess auszuführen, fügen Sie Folgendes zum Service-Tag hinzu:

    android:process=":qt_service"
  • Wenn Sie „ QtService “ erweitern, müssen Sie weitere Einträge deklarieren, um alle für Qt erforderlichen Bibliotheken zu laden – im Wesentlichen dieselben Einträge wie im Abschnitt „ <activity> “ für „ QtActivity “. Fügen Sie Folgendes hinzu:
    <service android:process=":qt_service" android:name=".QtAndroidService" android:exported="true">
        <meta-data android:name="android.app.lib_name" android:value="service"/>
        <meta-data android:name="android.app.background_running" android:value="true"/>
    </service>

Hinweis: Stellen Sie sicher, dass Sie Folgendes definieren, um den Dienst im Hintergrund auszuführen:

<meta-data android:name="android.app.background_running" android:value="true"/>

Es gibt verschiedene Möglichkeiten, Dienste zu deklarieren. Einige davon wurden bereits im vorherigen Manifest-Ausschnitt verwendet. Je nach Anwendungsfall können Sie den Dienst entweder im selben Prozess wie QtActivity oder in einem separaten Prozess ausführen.

Dienst im selben Prozess wie QtActivity

Um einen Dienst im selben Prozess wie QtActivity auszuführen, deklarieren Sie den Dienst-Header wie folgt:

<service android:name=".QtAndroidService" android:exported="true">

Dienst in einem separaten Prozess

Um einen Dienst in einem eigenen Prozess auszuführen, deklarieren Sie den Dienst-Header wie folgt:

<service android:process=":qt_service" android:name=".QtAndroidService" android:exported="true">

Qt lädt die unter android.app.lib_name meta-data definierte Datei „ .so “ und ruft die Funktion „ main() “ mit allen unter android.app.arguments meta-data festgelegten Argumenten auf. Bei der Ausführung in einem separaten Prozess können Sie den Dienst entweder mit derselben LIB-Datei wie die Hauptaktivität oder mit einer separaten LIB-Datei starten.

Verwenden Sie dieselbe .so-Lib-Datei

Wenn Sie dieselbe „ .so “-Lib-Datei wie die Hauptaktivität verwenden, bedeutet dies, dass der Dienst denselben Einstiegspunkt mit einem zusätzlichen Argument nutzt, um ihn von der Hauptaktivität zu unterscheiden. Sie können die Ausführung Ihrer Anwendung in der Funktion „ main() “ entsprechend den übergebenen Argumenten steuern. Fügen Sie die folgende Argumentdeklaration in den Hauptteil Ihres Dienstes ein:

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

Stellen Sie anschließend sicher, dass der Dienst „ android.app.lib_name “ mit dem der Hauptaktivität übereinstimmt, und fügen Sie Folgendes hinzu:

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

Wenn Sie dieselbe „ .so “-Lib-Datei verwenden, wird die Funktion „ main() “ Ihrer Anwendung zweimal ausgeführt: einmal zum Starten der Hauptaktivität und ein zweites Mal zum Starten des Dienstes. Daher müssen Sie jede Ausführung entsprechend dem übergebenen Argument behandeln. Eine Möglichkeit, dies zu erreichen, ist wie folgt:

if (argc <= 1) {
    // Code zur Behandlung der Ausführung der Hauptaktivität
} else if (argc > 1&& strcmp(argv[1], "-service")== 0) {
    qDebug() << "Service starting with from the same .so file";
    QAndroidService app(argc, argv);
    return app.exec();
} else {
    qWarning() << "Unrecognized command line argument";
   return-1;
}
Verwenden Sie eine separate .so-Bibliotheksdatei

In diesem Fall benötigen Sie ein Unterprojekt mit einer „ lib “-Vorlage, die eine andere ausführbare Datei für den Dienst bereitstellt. Ein Beispielprojekt sieht wie folgt aus:

  • In CMake:
    find_package(Qt6 REQUIRED COMPONENTS Core)
    
    qt_add_library(service SHARED
        servicemessenger.h
        service_main.cpp
    )
    
    target_link_libraries(service
        PRIVATE
            Qt::Core
            Qt::CorePrivate
    )
  • In qmake:
    TEMPLATE = lib
    TARGET = service
    CONFIG += dll
    QT += core core-private
    
    SOURCES += \
        service_main.cpp
    
    HEADERS += servicemessenger.h

In der Datei „ service_main.cpp “ könnte Folgendes stehen:

#include <QDebug>
#include <QAndroidService>
#include <QtCore/private/qandroidextras_p.h>

int main(int argc, char *argv[])
{
    qWarning() << "Service starting from a separate .so file";
    QAndroidService app(argc, argv);

    return app.exec();
}

Definieren Sie die ` android.app.lib_name ` für den Dienst in der Datei ` AndroidManifest.xml`:

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

Kommunikation mit dem Dienst

Qt für Android bietet eine Vielzahl von Methoden zur Interprozesskommunikation (IPC) für die Kommunikation mit Android-Diensten. Je nach Struktur Ihres Projekts können Sie entweder native C++-Aufrufe aus dem Java-Dienst oder einen Android-BroadcastReceiver verwenden.

Native C++-Aufrufe aus einem Java-Dienst

Dies funktioniert bei Diensten, die im selben Prozess wie „ QtActivity “ laufen, und sogar dann, wenn „ Service “ erweitert wurde.

Weitere Informationen finden Sie im Beispiel „Qt for Android Notifier“.

Verwendung von Android BroadcastReceiver

Der Android-BroadcastReceiver ermöglicht den Austausch von Nachrichten zwischen dem Android-System, Apps, Aktivitäten und Diensten. Ähnlich wie bei anderen Android-Funktionen kann Qt BroadcastReceiver nutzen, um Nachrichten zwischen „ QtActivity “ und Ihrem Dienst auszutauschen. Beginnen wir mit der Logik zum Senden einer Nachricht aus Ihrem Dienst. Fügen Sie in Ihrer Dienstimplementierung den folgenden Code hinzu, der `sendBroadcast()` aufruft:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    int ret = super.onStartCommand(intent, flags, startId);

    Intent sendToUiIntent = new Intent();
    sendToUiIntent.setAction(ActivityUtils.BROADCAST_CUSTOM_ACTION);
    sendToUiIntent.putExtra("message", "simple_string");

    Log.i(TAG, "Service sending broadcast");
    sendBroadcast(sendToUiIntent);

    return ret;
}

Anschließend müssen Sie den Broadcast-Receiver in der Hauptaktivität von Qt erstellen und registrieren. Am einfachsten ist es, eine benutzerdefinierte Klasse mit einer Methode zu erstellen und die gesamte Logik in Java zu implementieren. Im folgenden Beispiel sendet der Dienst eine Nachricht „ "simple_string" “ an Qt, indem er die native Methode ` sendToQt()` aufruft:

public class ServiceBroadcastUtils {

    private static native void sendToQt(String message);

    private static final String TAG = "ActivityUtils";
    public static final String BROADCAST_CUSTOM_ACTION = "org.qtproject.example.qtandroidservice.broadcast.custom";

    public void registerServiceBroadcastReceiver(Context context) {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BROADCAST_CUSTOM_ACTION);
        context.registerReceiver(serviceMessageReceiver, intentFilter);
        Log.i(TAG, "Registered broadcast receiver");
    }

    private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "In OnReceive()");
            if (BROADCAST_CUSTOM_ACTION.equals(intent.getAction())) {
                String message = intent.getStringExtra("message");
                sendToQt(message);
                Log.i(TAG, "Service sent back message to C++: " + message);
            }
        }
    };
}

Um all dies zu nutzen, starten Sie Ihren Dienst wie unter „Dienst starten“ beschrieben und registrieren Sie anschließend den Broadcast-Receiver durch Aufruf der Methode „ registerServiceBroadcastReceiver() “:

QJniEnvironment env;
jclass javaClass = env.findClass("org/qtproject/example/qtandroidservice/ActivityUtils");
QJniObject classObject(javaClass);
const QJniObject context(QNativeInterface::QAndroidApplication::context());
classObject.callMethod<void>("registerServiceBroadcastReceiver",
                             "(Landroid/content/Context;)V",
                             context.object());

Verwendung Qt Remote Objects

Qt Remote Objects bietet eine einfache Möglichkeit, APIs zwischen Qt-Prozessen gemeinsam zu nutzen. Das Grundkonzept besteht darin, den Dienst im Dienstprozess auszuführen und eine Replik in der Qt-Anwendung zu haben; dann können diese beiden Teile mithilfe von Signalen und Slots Daten untereinander austauschen.

Vorbereitung der Replik

Betrachten wir ein Service-Beispiel mit einer separaten ` .so `-Lib-Datei. Definieren Sie eine ` .rep `-Datei, in der unsere Kommunikationsklasse definiert ist:

class ServiceMessenger {
    SLOT(void ping(const QString &message));
    SIGNAL(pong(const QString &message));
}

Definieren Sie die Klasse dann im Service-Unterprojekt als „ servicemessenger.h “:

#include "rep_servicemessenger_source.h"

class ServiceMessenger : public ServiceMessengerSource {
public slots:
    void ping(const QString &name) override {
        emit pong("Hello " + name);
    }
};

Fügen Sie anschließend die Datei „ .rep “ sowohl zur Hauptanwendung als auch zum Service in der Hauptanwendung hinzu.

  • In CMake:
    find_package(Qt6 REQUIRED COMPONENTS RemoteObjects)
    
    qt_add_repc_replicas(service
        ../servicemessenger.rep
    )
    
    target_link_libraries(service PRIVATE Qt6::RemoteObjects)
  • In qmake:
    QT += remoteobjects
    REPC_REPLICA += servicemessenger.rep

Und im Unterprojekt „service“:

  • In CMake:
    find_package(Qt6 REQUIRED COMPONENTS RemoteObjects)
    
    qt_add_repc_sources(service
        ../servicemessenger.rep
    )
    target_link_libraries(service PRIVATE Qt6::RemoteObjects)
  • In qmake:
    QT += remoteobjects
    REPC_SOURCE += servicemessenger.rep

Verbinden Sie die Quelle und die Replik

Definieren Sie den Quellknoten „ Qt Remote Objects “ in der Funktion „ main() “ des Unterprojekts „service“:

#include "servicemessenger.h"

#include <QDebug>
#include <QAndroidService>
#include <QtCore/private/qandroidextras_p.h>

int main(int argc, char *argv[])
{
    qWarning() << "QtAndroidService starting from separate .so";
    QAndroidService app(argc, argv);

    QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")));
    ServiceMessenger serviceMessenger;
    srcNode.enableRemoting(&serviceMessenger);

    return app.exec();
}

Stellen Sie anschließend in der Funktion ` main() ` der Anwendung eine Verbindung zum Quellknoten her:

QRemoteObjectNode repNode;
repNode.connectToNode(QUrl(QStringLiteral("local:replica")));
QSharedPointer<ServiceMessengerReplica> rep(repNode.acquire<ServiceMessengerReplica>());
bool res = rep->waitForSource();
Q_ASSERT(res);

QObject::connect(rep.data(), &ServiceMessengerReplica::pong, [](const QString&message){
    qDebug() << "Service sent: " << message;
});
rep->ping("Qt und Android sind Freunde!");

In diesem Beispiel wird eine Nachricht vom Prozess der Hauptanwendung an den Dienst gesendet. Der Dienst antwortet mit derselben Nachricht, die im Debug-Logcat ausgegeben wird.

Hinweis: Die gleiche Methode kann verwendet werden, wenn dieselbe .so -Lib-Datei verwendet wird. Weitere Informationen finden Sie unter „Verwenden derselben .so-Lib-Datei“.

Verwendung von QAndroidBinder

QAndroidBinder ist eine Komfortklasse, die die Interprozesskommunikation ermöglicht, indem sie die wichtigsten Methoden von Binder implementiert. Sie ermöglicht das Senden von „ QByteArray “- oder „ QVariant “-Objekten zwischen Prozessen.

Hinweis: Qt für Android unterliegt einer Einschränkung, die vorschreibt, dass bei der Ausführung mehrerer Dienste in einem Prozess jeweils nur ein Dienst gleichzeitig ausgeführt werden darf. Daher wird empfohlen, jeden Dienst in einem eigenen Prozess auszuführen. Weitere Informationen finden Sie unter QTBUG-78009.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.