Android-Dienste
Beginnend mit Qt 5.7 können Sie mit Qt Android-Dienste erstellen. Ein Dienst ist eine Komponente, die im Hintergrund läuft, also keine Benutzeroberfläche hat. Er ist nützlich, um langfristige Operationen durchzuführen, wie z. B. das Aufzeichnen von GPS-Daten, das Warten auf Benachrichtigungen in sozialen Medien usw. Ein Dienst wird auch dann weiter ausgeführt, wenn die Anwendung, die ihn gestartet hat, beendet wird.
Zusammenstellen des Dienstes
Erstellen Sie zunächst ein Android-Paketverzeichnis, wie in Qt Creator beschrieben: Bereitstellen von Anwendungen auf Android-Geräten. Dieses Verzeichnis enthält die Datei AndroidManifest.xml
. Erstellen Sie innerhalb des Paketverzeichnisses ein Verzeichnis src
, in dem alle Ihre Java-Pakete und -Klassen erstellt werden.
Erstellen Sie die Dienstklasse
Sie können einen Dienst erstellen, indem Sie die Klasse QtService
oder Android: Service zu Ihrer Java-Klasse erweitern. Je nachdem, ob Sie in Ihrem Dienst Qt-Funktionen verwenden oder native C++-Funktionen von Java aus aufrufen möchten, müssen Sie entweder QtService
oder Service
erweitern. 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 erlaubt das Starten von Diensten bei Bedarf oder beim Booten. Sie können beides auch mit Qt tun.
Einen Dienst bei Bedarf starten
Sie können den Dienst auf die folgenden Arten starten:
- Direkt aus C++ unter Verwendung von QAndroidIntent und QJniObject, indem Sie einen Dienst-Intent erstellen und die Hauptaktivitätsmethode startService() der Anwendung aufrufen:
auto activity = QJniObject(QNativeInterface::QAndroidApplication::context()); QAndroidIntent serviceIntent(activity.object(), "org/qtproject/example/qtandroidservice/QtAndroidService"); QJniObject result = activity.callObjectMethod( "startService", "(Landroid/content/Intent;)Landroid/content/ComponentName;", serviceIntent.handle().object());
- Starten Sie den Dienst durch den 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)); }
Dann können Sie sie von C++ aus mit dem folgenden JNI-Aufruf aufrufen:
const QJniObject context(QNativeInterface::QAndroidApplication::context()); QJniObject::callStaticMethod<void>( "org/qtproject/example/qtandroidservice/QtAndroidService", "startQtAndroidService", "(Landroid/content/Context;)V", context.object());
Starten eines Dienstes zur Boot-Zeit
Um einen Dienst beim Booten zu starten, 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 die folgende uses-permission
in den Body 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 receiver
in den 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>
Hinweis: Mit Android 8.0 wurden einige Einschränkungen für die Ausführung 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 Foreground Services oder JobIntentService zu verwenden.
Verwalten des Dienstes in AndroidManifest.xml
Damit der Dienst in einer Android-App verwendet werden kann, müssen Sie ihn in der Datei AndroidManifest.xml
deklarieren. Beginnen wir mit dem Hinzufügen des Dienstabschnitts:
- Wenn Sie
Service
erweitern, deklarieren Sie den Dienstabschnitt einfach wie einen normalen Android-Dienst. Fügen Sie innerhalb des Abschnitts<application>
Folgendes hinzu:<service android:name=".QtAndroidService" android:exported="true"> <!-- Background running --> <meta-data android:name="android.app.background_running" android:value="true"/> <!-- Background running --> </service>
Auf diese Weise wird der Dienst im selben Prozess wie
QtActivity
gestartet, was es Ihnen ermöglicht, native C++-Aufrufe von Java-Code aus zu verwenden. Sie können ihn in einem separaten Prozess ausführen, aber dann können Sie keine nativen Aufrufe für die Kommunikation verwenden, da die Qt-Bibliotheken für diesen Prozess nicht geladen werden. Um es in einem separaten Prozess laufen zu lassen, fügen Sie dies dem Service-Tag hinzu:android:process=":qt_service"
- Wenn Sie
QtService
erweitern, müssen Sie weitere Elemente deklarieren, um alle für Qt erforderlichen Bibliotheken zu laden, hauptsächlich die gleichen Elemente wie im Abschnitt<activity>
fürQtActivity
. Fügen Sie das Folgende 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 das Folgende definieren, um den Dienst im Hintergrund laufen zu lassen:
<meta-data android:name="android.app.background_running" android:value="true"/>
Es gibt einige Varianten, wie man Dienste deklarieren kann. Einige von ihnen werden bereits im vorherigen Manifestausschnitt verwendet. Je nach Anwendungsfall führen Sie den Dienst entweder im selben Prozess wie QtActivity oder in einem separaten Prozess aus.
Dienst im gleichen Prozess wie QtActivity
Um einen Dienst im selben Prozess wie QtActivity laufen zu lassen, deklarieren Sie den Dienst-Header wie folgt:
<service android:name=".QtAndroidService" android:exported="true">
Dienst in separatem Prozess
Um einen Dienst in einem eigenen Prozess laufen zu lassen, deklarieren Sie den Service-Header wie folgt:
<service android:process=":qt_service" android:name=".QtAndroidService" android:exported="true">
Qt lädt die Datei .so
, die in android.app.lib_name
meta-data
definiert ist, und ruft die Funktion main()
mit allen Argumenten auf, die in android.app.arguments
meta-data
festgelegt sind. Wenn der Dienst in einem separaten Prozess ausgeführt wird, können Sie ihn entweder über die gleiche Lib-Datei wie die Hauptaktivität oder über eine separate Lib-Datei starten.
Verwenden Sie die gleiche .so Lib-Datei
Die Verwendung der gleichen .so
Lib-Datei wie die Hauptaktivität bedeutet, dass der Dienst den gleichen Einstiegspunkt mit einem zusätzlichen Argument verwendet, um ihn von der Hauptaktivität zu unterscheiden. Sie können die Ausführung Ihrer Anwendung in der Funktion main()
entsprechend den bereitgestellten Argumenten steuern. Fügen Sie die folgende Argumentdeklaration zu Ihrem Dienstkörper hinzu:
<!-- Application arguments --> <meta-data android:name="android.app.arguments" android:value="-service"/> <!-- Application arguments -->
Stellen Sie dann sicher, dass der Dienst android.app.lib_name
derselbe ist wie die Hauptaktivität, 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 das zweite Mal zum Starten des Dienstes. Daher müssen Sie jede Ausführung entsprechend dem angegebenen Argument behandeln. Eine Möglichkeit, dies zu erreichen, ist die folgende:
if (argc <= 1) { // Code für die 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; }
Verwendung einer separaten .so Lib-Datei
In diesem Fall müssen Sie ein Unterprojekt mit einer lib
Vorlage haben, die eine andere ausführbare Datei für den Dienst bereitstellt. Ein Beispielprojekt .pro
ist:
TEMPLATE = lib TARGET = service CONFIG += dll QT += core core-private SOURCES += \ service_main.cpp HEADERS += servicemessenger.h
In der service_main.cpp
könnten Sie folgendes haben:
#include <QDebug>#include <QAndroidService>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 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), um mit Android-Diensten zu kommunizieren. Je nach der Struktur Ihres Projekts können Sie entweder native C++-Aufrufe von Java Service oder Android BroadcastReceiver verwenden.
Native C++-Aufrufe von Java Service
Dies kann mit Diensten funktionieren, die im selben Prozess wie QtActivity
laufen, und sogar wenn Service
erweitert ist.
Weitere Informationen finden Sie im Qt Android Notifier-Beispiel.
Android BroadcastReceiver verwenden
Android BroadcastReceiver ermöglicht den Austausch von Nachrichten zwischen dem Android-System, Anwendungen, Aktivitäten und Diensten. Ähnlich wie bei anderen Android-Funktionen kann Qt BroadcastReceiver verwenden, um Nachrichten zwischen QtActivity
und Ihrem Dienst auszutauschen. Beginnen wir mit der Logik zum Senden einer Nachricht von Ihrem Dienst. Fügen Sie das Folgende in Ihre Service-Implementierung ein, die 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; }
Dann müssen Sie den Broadcast-Empfänger in der Hauptaktivität von Qt erstellen und registrieren. Am einfachsten ist es, eine eigene 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(data); Log.i(TAG, "Service sent back message to C++: " + message); } } }; }
Um all das zu nutzen, starten Sie Ihren Dienst wie in Start the Service gezeigt, und registrieren Sie dann den Broadcast-Empfänger, indem Sie die Methode registerServiceBroadcastReceiver()
aufrufen:
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 von Qt Remote Objects
Qt Remote Objects bietet eine einfache Möglichkeit, APIs zwischen Qt-Prozessen zu teilen. Das Hauptkonzept besteht darin, einen Server im Serviceprozess und eine Replik in der Qt-Anwendung zu haben. Diese beiden Teile können dann unter Verwendung von Signalen und Slots Daten untereinander austauschen.
Bereiten Sie die Replik vor
Betrachten wir ein Service-Beispiel mit separater .so
lib-Datei. Definieren Sie eine .rep
Datei, die unsere Kommunikationsklasse definiert:
class ServiceMessenger { SLOT(void ping(const QString &message)); SIGNAL(pong(const QString &message)); }
Definieren Sie die Klasse 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 dann die Datei .rep
sowohl der Hauptanwendung als auch dem Dienst .pro
in der Hauptanwendung hinzu:
QT += remoteobjects REPC_REPLICA += servicemessenger.rep
Und im Unterprojekt des Dienstes:
QT += remoteobjects REPC_SOURCE += servicemessenger.rep
Verbinden Sie die Quelle und das Replikat
Definieren Sie den Quellknoten Qt Remote Objects in der Funktion main()
des Dienstunterprojekts:
#include "servicemessenger.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"))); ServiceMessenger serviceMessenger; srcNode.enableRemoting(&serviceMessenger); return app.exec(); }
Stellen Sie dann 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 der gleichen Nachricht, die im Debug-Logcat ausgegeben wird.
Hinweis: Die gleiche Methode kann verwendet werden, wenn die gleiche .so
lib-Datei verwendet wird. Weitere Informationen finden Sie unter Verwenden der gleichen .so Lib-Datei.
QAndroidBinder verwenden
QAndroidBinder ist eine Komfortklasse, die die Kommunikation zwischen Prozessen ermöglicht, indem sie die wichtigsten Methoden in Android implementiert : Binder. Sie ermöglicht das Senden von QByteArray oder QVariant Objekten zwischen Prozessen.
Hinweis: Qt für Android hat eine Einschränkung, die die Ausführung von nur einem Dienst zur gleichen Zeit erzwingt, wenn mehrere Dienste in einem Prozess ausgeführt werden. Es wird daher empfohlen, jeden Dienst in einem eigenen Prozess auszuführen. Für weitere Informationen siehe QTBUG-78009.
© 2025 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.