Services Android
Vous pouvez créer des services Android à l'aide de Qt. Un service est un composant qui s'exécute en arrière-plan ; il ne dispose donc pas d'interface utilisateur. Il est utile pour effectuer des opérations de longue durée, telles que l'enregistrement de données GPS, l'attente de notifications sur les réseaux sociaux, etc. Un service continue de s'exécuter même si l'application qui l'a lancé se ferme.
Mise en place du service
Pour commencer, créez un répertoire de package Android en suivant les instructions fournies dans la section « Étendre Qt avec les fonctionnalités Android ». Ce répertoire contient le fichier ` AndroidManifest.xml `. À l’intérieur du répertoire du package, créez un répertoire ` src `, dans lequel seront créés tous vos packages et classes Java.
Créer la classe de service
Lorsque vous décidez d’utiliser ` QtService ` ou `Android Service`, le même raisonnement que pour `Activity` s’applique ici. À moins que vous n’utilisiez des fonctionnalités nécessitant le chargement des bibliothèques Qt, telles que les appels natifs et la gestion des événements de Qt, l’extension de ` Service ` devrait fonctionner.
Vous pouvez créer un service en héritant de la classe ` QtService ` ou `Service` dans votre classe Java. Selon que vous souhaitiez utiliser des fonctionnalités Qt dans votre service ou appeler des fonctions C++ natives depuis Java, vous devrez hériter soit de ` QtService `, soit de ` Service`. Commençons par un service simple, comme suit :
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;
}
}Démarrer le service
Android permet de démarrer des services à la demande ou au démarrage du système. Vous pouvez également effectuer ces deux opérations à l’aide de Qt.
Démarrer un service à la demande
Vous pouvez démarrer le service de différentes manières :
- Directement depuis C++ à l'aide de QAndroidIntent et QJniObject, en créant un Intent de service et en appelant la méthode startService() de l'activité principale de l'application :
// 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); - Lancez le service en appelant une méthode Java. La méthode la plus simple consiste à créer une méthode statique dans votre classe de service :
public static void startQtAndroidService(Context context) { context.startService(new Intent(context, QtAndroidService.class)); }Vous pouvez ensuite l'appeler depuis C++ à l'aide de l'appel JNI suivant :
using namespace QtJniTypes; using namespace QNativeInterface; // ... auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>(); Q_ASSERT(androidApp); Context context = androidApp->context(); QtAndroidService::callStaticMethod<void>("startQtAndroidService", context);
Démarrer un service au démarrage du système
Pour exécuter un service au démarrage, vous avez besoin d'un BroadcastReceiver.
Créez une classe Java personnalisée :
public class QtBootServiceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, QtAndroidService.class);
context.startService(startServiceIntent);
}
}Ajoutez l'uses-permission suivante dans le corps de la section <manifest> du fichier AndroidManifest.xml:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />Ajoutez également la définition de l’ receiver dans le corps de la section <application>:
<receiver android:name=".QtBootServiceBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>Limitations
- Android 15.0 a introduit certaines limitations concernant le lancement de services en avant-plan après la réception de BOOT_COMPLETED. Pour plus d’informations, consultez la section Restrictions relatives à BOOT_COMPLETED.
- Android 8.0 a introduit certaines restrictions concernant l'exécution des services en arrière-plan, ce qui signifie que l'utilisation d'une classe `
Service` standard pourrait ne pas fonctionner. Pour plus d'informations, consultez la recommandation d'Android d'utiliser soit les services en premier plan, soit `JobIntentService`.
Gérer le service dans AndroidManifest.xml
Pour que le service soit utilisable dans une application Android, vous devez le déclarer dans le fichier AndroidManifest.xml. Commençons par ajouter la section relative au service :
- Lorsque vous étendez le fichier `
Service`, il suffit de déclarer la section du service comme un service Android classique. Ajoutez ce qui suit à l'intérieur de la section `<application>` :<service android:name=".QtAndroidService" android:exported="true"> <meta-data android:name="android.app.background_running" android:value="true"/> </service>De cette manière, le service démarrera dans le même processus que `
QtActivity`, ce qui vous permet d’utiliser des appels C++ natifs depuis du code Java. Vous pouvez l’exécuter dans un processus distinct, mais dans ce cas, vous ne pourrez pas utiliser d’appels natifs pour la communication, car les bibliothèques Qt ne sont pas chargées pour ce processus. Pour l’exécuter dans un processus distinct, ajoutez ceci à la balise `service` :android:process=":qt_service" - Lorsque vous étendez
QtService, vous devez déclarer d’autres éléments pour charger toutes les bibliothèques nécessaires à Qt, principalement les mêmes éléments que ceux de la section<activity>pourQtActivity. Ajoutez ce qui suit :<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>
Remarque : veillez à définir les éléments suivants pour que le service s'exécute en arrière-plan :
<meta-data android:name="android.app.background_running" android:value="true"/>Il existe plusieurs façons de déclarer des services. Certaines d’entre elles sont déjà utilisées dans l’extrait de manifeste précédent. En fonction de votre cas d’utilisation, exécutez le service soit dans le même processus que QtActivity, soit dans un processus distinct.
Service dans le même processus que QtActivity
Pour exécuter un service dans le même processus que QtActivity, déclarez l'en-tête du service comme suit :
<service android:name=".QtAndroidService" android:exported="true">Service dans un processus distinct
Pour exécuter un service dans un processus dédié, déclarez l'en-tête du service comme suit :
<service android:process=":qt_service" android:name=".QtAndroidService" android:exported="true">Qt charge le fichier « .so » défini dans android.app.lib_name meta-data , et appelle la fonction « main() » avec tous les arguments définis dans android.app.arguments meta-data . Lorsqu’il s’exécute dans un processus séparé, vous pouvez démarrer le service en utilisant soit le même fichier «lib» que l’activité principale, soit un fichier «lib» distinct.
Utiliser le même fichier .so
Utiliser le même fichier de bibliothèque « .so » que l’activité principale signifie que le service utilisera le même point d’entrée avec un argument supplémentaire pour le distinguer de l’activité principale. Vous pouvez gérer l’exécution de votre application dans la fonction « main() » en fonction des arguments fournis. Ajoutez la déclaration d’argument suivante au corps de votre service :
<meta-data android:name="android.app.arguments" android:value="-service"/>Assurez-vous ensuite que le service android.app.lib_name est identique à celui de l’activité principale, puis ajoutez ce qui suit :
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>Lorsque vous utilisez le même fichier de bibliothèque « .so », la fonction ` main() ` de votre application est exécutée deux fois : une première fois pour lancer l’activité principale, et une seconde fois pour lancer le service. Vous devez donc gérer chaque exécution en fonction de l’argument fourni. Voici une façon de procéder :
if (argc <= 1) {
// code pour gérer l'exécution de l'activité principale
} 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;
}Utiliser un fichier de bibliothèque .so distinct
Dans ce cas, vous devez disposer d'un sous-projet avec un modèle lib qui fournit un exécutable différent pour le service. Voici un exemple de projet :
- Dans 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 ) - Dans qmake :
TEMPLATE = lib TARGET = service CONFIG += dll QT += core core-private SOURCES += \ service_main.cpp HEADERS += servicemessenger.h
Dans le fichier « service_main.cpp », vous pourriez avoir ce qui suit :
#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();
}Définissez l'android.app.lib_name du service dans le fichier « AndroidManifest.xml » :
<meta-data android:name="android.app.lib_name" android:value="service"/>Communication avec le service
Qt pour Android propose diverses méthodes de communication interprocessus (IPC) pour communiquer avec les services Android. En fonction de la structure de votre projet, vous pouvez utiliser soit des appels C++ natifs depuis un service Java, soit un BroadcastReceiver Android.
Appels C++ natifs depuis un service Java
Cette méthode fonctionne avec les services s'exécutant dans le même processus que l'QtActivity, même si celui-ci est une extension de l'Service.
Pour plus d’informations, consultez l’exemple « Qt for Android Notifier ».
Utilisation de BroadcastReceiver sous Android
Le BroadcastReceiver Android permet l'échange de messages entre le système Android, les applications, les activités et les services. À l'instar d'autres fonctionnalités Android, Qt peut utiliser des récepteurs de diffusion pour échanger des messages entre QtActivity et votre service. Commençons par la logique permettant d'envoyer un message depuis votre service. Ajoutez le code suivant dans l'implémentation de votre service, qui appelle la fonction sendBroadcast():
@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;
}Ensuite, vous devez créer et enregistrer le récepteur de diffusion à partir de l’activité principale de Qt. Le plus simple est de créer une classe personnalisée comportant une méthode et d’implémenter toute cette logique en Java. Dans l’exemple suivant, le service envoie un message « "simple_string" » à Qt en appelant la méthode native ` sendToQt()` :
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);
}
}
};
}Pour tirer parti de tout cela, lancez votre service comme indiqué dans la section « Démarrer le service », puis enregistrez le récepteur de diffusion en appelant la méthode 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());Utilisation Qt Remote Objects
Qt Remote Objects offre un moyen simple de partager des API entre des processus Qt. Le principe consiste à exécuter le service dans le processus dédié et à disposer d’une réplique dans l’application Qt ; ces deux éléments peuvent alors échanger des données entre eux à l’aide de signaux et de slots.
Préparer la réplique
Prenons l’exemple d’un service avec un fichier lib d’ .so s distinct. Définissons un fichier ` .rep ` qui définit notre classe de communication :
class ServiceMessenger {
SLOT(void ping(const QString &message));
SIGNAL(pong(const QString &message));
}Définissez ensuite la classe dans le sous-projet du service en tant qu’ servicemessenger.h:
#include "rep_servicemessenger_source.h"
class ServiceMessenger : public ServiceMessengerSource {
public slots:
void ping(const QString &name) override {
emit pong("Hello " + name);
}
};Ensuite, ajoutez le fichier ` .rep ` à la fois à l'application principale et au service au sein de l'application principale.
- Dans CMake :
find_package(Qt6 REQUIRED COMPONENTS RemoteObjects) qt_add_repc_replicas(service ../servicemessenger.rep ) target_link_libraries(service PRIVATE Qt6::RemoteObjects) - Dans qmake :
QT += remoteobjects REPC_REPLICA += servicemessenger.rep
Et dans le sous-projet « service » :
- Dans CMake :
find_package(Qt6 REQUIRED COMPONENTS RemoteObjects) qt_add_repc_sources(service ../servicemessenger.rep ) target_link_libraries(service PRIVATE Qt6::RemoteObjects) - Dans qmake :
QT += remoteobjects REPC_SOURCE += servicemessenger.rep
Connecter la source et la réplique
Définissez le nœud source « Qt Remote Objects » dans la fonction « main() » du sous-projet « 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();
}Ensuite, dans la fonction main() de l'application, connectez-vous au nœud source :
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 et Android font bon ménage !");Cet exemple envoie un message depuis le processus de l’application principale vers le service. Le service répond avec le même message, qui s’affiche dans le journal de débogage Logcat.
Remarque : cette méthode peut également être utilisée lorsque l'on utilise le même fichier de bibliothèque .so. Pour plus d'informations, consultez la section « Utilisation du même fichier de bibliothèque .so ».
Utilisation de QAndroidBinder
QAndroidBinder est une classe utilitaire qui permet la communication inter-processus en implémentant les méthodes les plus importantes de Binder. Elle permet d'envoyer des objets de type « QByteArray » ou « QVariant » entre les processus.
Remarque : Qt pour Android présente une limitation qui impose l'exécution d'un seul service à la fois lorsque plusieurs services sont exécutés au sein d'un même processus. Il est donc recommandé d'exécuter chaque service dans son propre processus. Pour plus d'informations, voir 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.