Spec-Zone.ru › Qt 6.1

Услуги Android

Начиная с Qt 5.7, вы можете создавать службы Android с помощью Qt. Служба — это компонент, который выполняется в фоновом режиме, поэтому у него нет пользовательского интерфейса. Это полезно для выполнения длительных операций, таких как регистрация GPS, ожидание уведомлений из социальных сетей и так далее. Служба будет продолжать работать даже если приложение, которое её запустило, завершит работу.

Сборка службы

Для начала создайте каталог пакета Android, как указано в Qt Creator: Развёртывание приложений на устройствах Android. Этот каталог содержит файл AndroidManifest.xml. Внутри каталога пакета создайте каталог src, где будут созданы все ваши Java-пакеты и классы.

Создание класса службы

Вы можете создать службу, расширив класс QtService или Android: Служба до вашего Java-класса. В зависимости от того, хотите ли вы использовать функции Qt в вашей службе или вызывать собственные функции C++ из Java, вам необходимо расширить либо QtService, либо Service. Давайте начнём с простой службы, как показано ниже:

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

Запуск службы

Android позволяет запускать службы по требованию или во время загрузки. Вы можете сделать это и с помощью Qt.

Запуск службы во время загрузки

Для запуска службы во время загрузки вам нужен BroadcastReceiver.

Создайте пользовательский Java-класс:

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

Добавьте следующий uses-permission в тело раздела <manifest> в файле AndroidManifest.xml:

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

Также добавьте определение receiver в тело раздела <application>:

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

Примечание: Android 8.0 ввёл некоторые ограничения на запуск фоновых служб, что означает, что использование обычного класса Service может не сработать. Более подробную информацию см. в рекомендации Android использовать либо Android: Foreground services{Фоновые службы} или JobIntentService.

Управление службой в AndroidMnifest.xml

Чтобы служба была доступна в приложении Android, вы должны объявить её в файле AndroidManifest.xml. Давайте начнём с добавления раздела службы:

  • При расширении Service, просто объявите раздел службы как обычную службу Android. Добавьте следующее в раздел <application>:
    <service android:name=".QtAndroidService">
        <!-- Background running -->
        <meta-data android:name="android.app.background_running" android:value="true"/>
        <!-- Background running -->
    </service>

    Таким образом, служба будет запускаться в том же процессе, что и QtActivity, что позволяет использовать вызовы собственного C++ из кода Java. Вы можете запустить её в отдельном процессе, но в этом случае вы не сможете использовать собственные вызовы для связи, поскольку библиотеки Qt не загружаются для этого процесса. Чтобы запустить в отдельном процессе, добавьте это к тегу службы:

    android:process=":qt_service"
  • При расширении QtService, вам нужно объявить другие элементы для загрузки всех необходимых библиотек, требуемых для Qt, в основном те же элементы, что и в разделе <activity> для QtActivity. Добавьте следующее:
    <service android:process=":qt_service" android:name=".QtAndroidService">
    
        <meta-data android:name="android.app.lib_name" android:value="service"/>
        <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
        <meta-data android:name="android.app.repository" android:value="default"/>
        <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
        <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
    
        <!-- Deploy Qt libs as part of package -->
        <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
    
        <!-- Run with local libs -->
        <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
        <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
        <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
        <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
        <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
        <!-- Run with local libs -->
    
        <!-- Background running -->
        <meta-data android:name="android.app.background_running" android:value="true"/>
        <!-- Background running -->
    </service>

Примечание: Убедитесь, что определены следующие параметры, чтобы служба работала в фоновом режиме:

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

Существует несколько вариантов объявления служб. Некоторые из них уже используются в предыдущем фрагменте манифеста. В зависимости от вашего случая, запустите службу либо в том же процессе, что и QtActivity, либо в отдельном процессе.

Служба в том же процессе, что и QtActivity

Чтобы запустить службу в том же процессе, что и QtActivity, объявите заголовок службы следующим образом:

<service android:name=".QtAndroidService">

Служба в отдельном процессе

Чтобы запустить службу в отдельном процессе, объявите заголовок службы следующим образом:

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

Qt загружает файл .so, определённый в android.app.lib_name meta-data, и вызывает функцию main() со всеми аргументами, установленных в android.app.arguments meta-data. При запуске в отдельном процессе вы можете запустить службу, используя либо тот же файл lib, что и основная активность, либо отдельный файл lib.

Использование одного и того же файла .so lib

Использование одного и того же файла .so lib, что и основной активностью, означает, что служба будет использовать ту же точку входа с дополнительным аргументом для различения её от основной активности. Вы можете обрабатывать выполнение вашего приложения в функции main() в соответствии с предоставленными аргументами. Добавьте следующее объявление аргумента в тело службы:

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

Затем убедитесь, что служба android.app.lib_name идентична основной активности, добавьте следующее:

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

При использовании одного и того же файла .so lib функция main() вашего приложения выполняется дважды, один раз для запуска основной активности и второй раз для запуска службы. Таким образом, вы должны обрабатывать каждое выполнение в соответствии с предоставленным аргументом. Один из способов достижения этого показан ниже:

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;
}
Использование отдельного файла .so lib

В этом случае вам необходимо иметь подпроект с шаблоном lib, который предоставляет отдельное исполняемое приложение для службы. Пример проекта .pro:

TEMPLATE = lib
TARGET = service
CONFIG += dll
QT += core androidextras

SOURCES += \
    service_main.cpp

HEADERS += servicemessenger.h

В service_main.cpp у вас может быть следующее:

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

Определите android.app.lib_name для службы в AndroidManifest.xml:

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

Взаимодействие со службой

Qt для Android предлагает различные методы межпроцессного взаимодействия (IPC) для взаимодействия со службами Android. В зависимости от структуры вашего проекта, вы можете использовать либо собственные вызовы C++ из Java-службы, либо Android BroadcastReceiver.

Вызовы собственного C++ из Java-службы

Это может работать со службами, работающими в том же процессе, что и QtActivity, и даже если Service расширен.

Использование QAndroidBinder

QAndroidBinder — это вспомогательный класс, который позволяет осуществлять межпроцессное взаимодействие, реализуя наиболее важные методы в Android: Binder. Он позволяет отправлять объекты QByteArray или QVariant между процессами.

Примечание: Qt для Android имеет ограничение, принудительно выполняющее только одну службу за раз при запуске нескольких служб в одном процессе. Поэтому рекомендуется запускать каждую службу в собственном процессе. Дополнительную информацию см. в QTBUG-78009.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.1/android-services.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API