Android Services | Qt 6.12
Description: Provides information about Android Services support in Qt.

- Qt 6.12
- Product information
- Supported Platforms
- Qt for Android
- Android Services
- Qt 6.12.0 Reference Documentation

Android Platform Notes ◦ Porting to Android

# Android Services

You can create Android services using Qt. A service is a component that runs in background, so, it has no user interface. It is useful to perform long-term operations such as logging GPS, waiting for social media notifications, and so on. A service will continue to run even if the application that started it exits.

## Assemble the Service

To get started, create an Android package directory as instructed in Extending Qt with Android Facilities. This directory contains the `AndroidManifest.xml` file. Inside the package directory, create a `src` directory, where all your Java packages and classes will be created.

### Create the Service Class

When deciding to use `QtService` or Android Service, the same reasoning as with Activity applies here. Unless you are using features that require the Qt libraries to be loaded, like Qt's native calls and event handling, extending `Service` should work.

You can create a service by extending the class `QtService` or Service to your Java class. Depending on whether you want to use Qt features in your service or call native C++ functions from Java, you need to extend either `QtService` or `Service`. Let's start with a simple service, as follows:

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

### Start the Service

Android allows starting services on demand or at boot time. You can do both using Qt as well.

#### Start a Service On Demand

You can start the service in the following ways:

- Directly from C++ using QAndroidIntent and QJniObject, by creating a service Intent and calling the app's main activity method 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);

- Start the service by calling a Java method. The easiest way is to create a static method in your service class:

       public static void startQtAndroidService(Context context) {
               context.startService(new Intent(context, QtAndroidService.class));
       }

  Then you can call it from C++ using the following JNI call:

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

#### Start a Service At Boot Time

To run a service at boot time, you need a BroadcastReceiver.

Create a custom Java class:

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

Add the following `uses-permission` in the body of the `<manifest>` section in the `AndroidManifest.xml` file:

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

Also, add the `receiver` definition in the body of the `<application>` section:

     <receiver android:name=".QtBootServiceBroadcastReceiver" android:exported="true">
         <intent-filter>
             <action android:name="android.intent.action.BOOT_COMPLETED" />
         </intent-filter>
     </receiver>

##### Limitations

- Android 15.0 introduced some limitations on launching foreground services, after receiving BOOT_COMPLETED. For more information, see Restrictions on BOOT_COMPLETED.
- Android 8.0 introduced some limitations on running background services, which means using a normal `Service` class might not work. For more information, see Android's recommendation to use either Foreground services or JobIntentService.

### Manage the Service in AndroidManifest.xml

For the service to be usable in an Android app, you must declare it in the `AndroidManifest.xml` file. Let's start with adding the service section:

- When extending `Service`, just declare the service section as a normal Android service. Add the following inside the `<application>` section:

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

  This way the service will start in the same process as `QtActivity`, which allows you to use native C++ calls from Java code. You can run it in a separate process but that way you cannot use any native calls for communication because the Qt libraries are not loaded for that process. To run on separate process, add this to the service tag:

       android:process=":qt_service"

- When extending `QtService`, you need to declare other items for loading all the necessary libs required for Qt, mainly the same items as in `<activity>` section for `QtActivity`. Add the following:

       <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: Make sure to define the following to run the service in the background:

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

There are a few variations on how to declare services. Some of them are already used in the previous manifest snippet. Depending on your use case, run the service either in the same process as QtActivity or in a separate process.

#### Service in the Same Process as QtActivity

To run a service in the same process as QtActivity, declare the service header as follows:

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

#### Service in Separate Process

To run a service in a dedicated process, declare the service header as follows:

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

Qt loads the `.so` file defined in `android.app.lib_name` `meta-data`, and calls the `main()` function with all the arguments set in `android.app.arguments` `meta-data`. When running in a separate process, you can start the service using either the same lib file as the main activity or a separate lib file.

##### Use the Same .so Lib File

Using the same `.so` lib file as the main activity means the service will use the same entry point with an extra argument to distinguish it from the main activity. You can handle your application's execution in the `main()` function according the arguments provided. Add the following argument declaration to your service body:

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

Then make sure the service `android.app.lib_name` is the same as the main activity, add the following:

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

When using the same `.so` lib file, your application's `main()` function is executed two times, one to start the main activity and the second time to start the service. Thus, you have to handle each execution according to the provided argument. One way to achieve that is as follows:

     if (argc <= 1) {
         // code to handle main activity execution
     } 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;
     }

##### Use a Separate .so Lib File

In this case, you need to have a sub-project with a `lib` template that provides a different executable for the service. A sample project is:

- 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 the `service_main.cpp` you could have the following:

     #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();
     }

Define the `android.app.lib_name` for the service in the `AndroidManifest.xml`:

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

## Communication with the Service

Qt for Android offers a variety of inter-process communication (IPC) methods to communicate with Android Services. Depending on the structure of your project, you can use either native C++ calls from Java Service or Android BroadcastReceiver.

### Native C++ Calls from Java Service

This can work with services running in the same process as `QtActivity` and even if `Service` is extended.

For more information, see the Qt for Android Notifier Example.

### Using Android BroadcastReceiver

Android BroadcastReceiver enables exchanging messages between the Android system, apps, activities and services. Similarly to other Android features, Qt can use broadcast receivers to exchange messages between `QtActivity` and your service. Let's start with logic to send a message from your service. Add the following in your service implementation, which calls 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;
     }

Then, you need to create and register the broadcast receiver from the Qt's main activity. The easiest way is to create a custom class with a method and implement all that logic in Java. In the following example, the service sends a message `"simple_string"` to Qt by calling the native method `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);
                 }
             }
         };
     }

To make use of all that, start your service as shown in Start the Service, an then register the broadcast receiver by calling the method `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());

### Using Qt Remote Objects

Qt Remote Objects offers an easy way to share APIs between Qt processes. The main concept is to server in the service process, and have a replica in the Qt application, then those two parts are able to exchange data between each other, using signals and slots.

#### Prepare the replica

Let's consider a service example with separate `.so` lib file. Define a `.rep` file which defines our communication class:

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

The define the class in the service sub-project as `servicemessenger.h`:

     #include "rep_servicemessenger_source.h"

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

Then, add the `.rep` file to both the main application and service in the main application.

- 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

And in the service sub-project:

- 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

#### Connect the source and replica

Define the Qt Remote Objects source node in the service sub-project's `main()` function:

     #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();
     }

Then, in the application's `main()` function, connect to source node:

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

This example sends a message from the main application's process to the service. The service replies with the same message, which is printed on the debug logcat.

Note: The same method could be used when using the same `.so` lib file. For more information, see Use the same .so Lib File.

### Using QAndroidBinder

QAndroidBinder is a convenience class that enables inter-process communication by implementing the most important methods in Binder. It allows sending QByteArray or QVariant objects between processes.

Note: Qt for Android has a limitation forcing the execution of only one service at a time when running multiple services in one process. Thus, it is recommended to run each service in its own process. For more information, see QTBUG-78009.

Android Platform Notes ◦ Porting to Android