Sur cette page

Services Android

Vous pouvez créer des services Android à l'aide de Qt. Un service est un composant qui fonctionne en arrière-plan et n'a donc pas d'interface utilisateur. Il est utile pour effectuer des opérations à long terme telles que l'enregistrement du GPS, l'attente de notifications de médias sociaux, etc. Un service continuera à fonctionner même si l'application qui l'a lancé se termine.

Assembler le service

Pour commencer, créez un répertoire de paquets Android comme indiqué dans Extending Qt with Android Facilities. Ce répertoire contient le fichier AndroidManifest.xml. Dans le répertoire package, créez un répertoire src, où tous vos paquets et classes Java seront créés.

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 qui nécessitent le chargement des bibliothèques Qt, comme les appels natifs de Qt et la gestion des événements, l'extension de Service devrait fonctionner.

Vous pouvez créer un service en étendant la classe QtService ou Service à votre classe Java. Selon que vous souhaitez utiliser les fonctionnalités de Qt dans votre service ou appeler des fonctions C++ natives à partir de Java, vous devez étendre soit QtService, soit 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. Vous pouvez également faire les deux en utilisant Qt.

Démarrer un service à la demande

Vous pouvez démarrer le service de la manière suivante :

  • Directement à partir de C++ en utilisant QAndroidIntent et QJniObject, en créant une intention de service et en appelant la méthode de l'activité principale de l'application startService():
    // 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);
  • Démarrer 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 à partir de C++ en utilisant 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

Pour lancer 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 la ligne suivante uses-permission 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 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>
Limites
  • Android 15.0 a introduit certaines limitations sur le lancement de services au premier plan, après avoir reçu BOOT_COMPLETED. Pour plus d'informations, voir Restrictions sur BOOT_COMPLETED.
  • Android 8.0 a introduit certaines limitations sur l'exécution des services d'arrière-plan, ce qui signifie que l'utilisation d'une classe Service normale peut ne pas fonctionner. Pour plus d'informations, voir la recommandation d'Android d'utiliser les services d'arrière-plan ou 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 du service :

  • Lors de l'extension de Service, il suffit de déclarer la section service comme un service Android normal. 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 à partir du code Java. Vous pouvez l'exécuter dans un processus séparé, mais dans ce cas, vous ne pouvez pas utiliser les 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 de service :

    android:process=":qt_service"
  • Lors de l'extension de QtService, vous devez déclarer d'autres éléments pour charger toutes les bibliothèques nécessaires pour Qt, principalement les mêmes éléments que dans la section <activity> pour QtActivity. 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>

Note : Assurez-vous de définir les éléments suivants pour exécuter le service en arrière-plan :

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

Il existe quelques variantes sur la manière de déclarer les 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 séparé.

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 séparé

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 XML 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 . Lors de l'exécution 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 séparé.

Utiliser le même fichier lib .so

L'utilisation du 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"/>

Ensuite, assurez-vous que le service android.app.lib_name est le même que l'activité principale, 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 .so lib, la fonction main() de votre application est exécutée deux fois, une fois pour démarrer l'activité principale et la seconde fois pour démarrer le service. Vous devez donc gérer chaque exécution en fonction de l'argument fourni. Une façon d'y parvenir est la suivante :

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 .so Lib séparé

Dans ce cas, vous devez avoir 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 site 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éfinir le android.app.lib_name pour le service dans le AndroidManifest.xml:

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

Communication avec le service

Qt pour Android offre une variété de méthodes de communication inter-processus (IPC) pour communiquer avec les services Android. En fonction de la structure de votre projet, vous pouvez utiliser les appels C++ natifs du service Java ou le récepteur de diffusion Android.

Appels C++ natifs du service Java

Cette méthode peut fonctionner avec des services s'exécutant dans le même processus que QtActivity et même si Service est étendu.

Pour plus d'informations, voir l'exemple de Notificateur Qt pour Android.

Utilisation de BroadcastReceiver Android

Android BroadcastReceiver permet d'échanger des messages entre le système Android, les applications, les activités et les services. De même que pour d'autres fonctionnalités d'Android, Qt peut utiliser des récepteurs de diffusion pour échanger des messages entre QtActivity et votre service. Commençons par la logique d'envoi d'un message à partir de votre service. Ajoutez ce qui suit dans l'implémentation de votre service, qui appelle 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 avec une méthode et d'implémenter toute cette logique en Java. Dans l'exemple suivant, le service envoie un message "simple_string" à Qt XML 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 utiliser tout cela, démarrez votre service comme indiqué dans 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 de Qt Remote Objects

Qt Remote Objects offre un moyen simple de partager les API entre les processus Qt. Le concept principal est d'avoir un serveur dans le processus de service, et d'avoir une réplique dans l'application Qt, puis ces deux parties sont capables d'échanger des données entre elles, en utilisant des signaux et des slots.

Préparer la réplique

Considérons un exemple de service avec un fichier .so lib séparé. Définissez un fichier .rep qui définit notre classe de communication :

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

La classe est définie dans le sous-projet de service comme 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 à l'application principale et au service dans 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éfinir le nœud source Qt Remote Objects dans la fonction main() du sous-projet de 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 and Android are friends !") ;

Cet exemple envoie un message du processus de l'application principale au service. Le service répond avec le même message, qui est imprimé sur le logcat de débogage.

Note : La même méthode peut être utilisée en utilisant le même fichier .so lib. Pour plus d'informations, voir Utiliser le même fichier lib .so.

Utilisation de QAndroidBinder

QAndroidBinder est une classe de commodité qui permet la communication inter-processus en implémentant les méthodes les plus importantes de Binder. Elle permet d'envoyer des objets QByteArray ou QVariant entre les processus.

Note : Qt pour Android a une limitation qui force l'exécution d'un seul service à la fois lors de l'exécution de plusieurs services dans un 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.