Службы переднего плана

Службы переднего плана выполняют операции, заметные пользователю.

Службы переднего плана отображают уведомление в строке состояния , чтобы пользователи знали, что ваше приложение выполняет задачу на переднем плане и потребляет системные ресурсы.

Примеры приложений, использующих службы переднего плана, включают следующее:

  • Приложение музыкального проигрывателя, воспроизводящее музыку в службе переднего плана. В уведомлении может отображаться воспроизводимая в данный момент песня.
  • Фитнес-приложение, которое записывает пробежку пользователя в службе переднего плана после получения разрешения от пользователя. В уведомлении может отображаться расстояние, которое пользователь преодолел во время текущей тренировки.

Используйте службу переднего плана только тогда, когда вашему приложению необходимо выполнить задачу, заметную для пользователя, даже если он не взаимодействует с приложением напрямую. Если действие имеет достаточно низкую важность и вы хотите использовать уведомление с минимальным приоритетом, вместо этого создайте фоновую задачу .

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

Пользователь может отклонить уведомление по умолчанию

Начиная с Android 13 (уровень API 33), пользователи могут по умолчанию отклонять уведомления, связанные со службой переднего плана. Для этого пользователи проводят жестом по уведомлению. Традиционно уведомление не отклоняется до тех пор, пока служба переднего плана не будет остановлена ​​или удалена с переднего плана.

Если вы хотите, чтобы пользователь не мог отклонить уведомление, передайте true в метод setOngoing() при создании уведомления с помощью Notification.Builder .

Сервисы, которые сразу показывают уведомление

Если служба переднего плана имеет хотя бы одну из следующих характеристик, система отображает соответствующее уведомление сразу после запуска службы, даже на устройствах под управлением Android 12 или более поздней версии:

В Android 13 (уровень API 33) или более поздней версии, если пользователь отказывает в разрешении на уведомление , он по-прежнему видит уведомления, связанные со службами переднего плана, в диспетчере задач , но не видит их в панели уведомлений.

Объявите службы переднего плана в своем манифесте

В манифесте вашего приложения объявите каждую из служб переднего плана вашего приложения с помощью элемента <service> . Для каждой службы используйте атрибут android:foregroundServiceType чтобы объявить, какую работу выполняет служба.

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
  <application ...>

    <service
        android:name=".MyMediaPlaybackService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="false">
    </service>
  </application>
</manifest>

Если к вашему сервису применимо несколько типов, разделите их | оператор. Например, служба, использующая камеру и микрофон, объявит об этом так:

android:foregroundServiceType="camera|microphone"

Запросить разрешения службы переднего плана

Приложения, предназначенные для Android 9 (уровень API 28) или выше и использующие службы переднего плана, должны запрашивать FOREGROUND_SERVICE в манифесте приложения, как показано в следующем фрагменте кода. Это обычное разрешение , поэтому система автоматически предоставляет его запрашивающему приложению.

Кроме того, если приложение нацелено на уровень API 34 или выше, оно должно запросить соответствующий тип разрешения для типа работы, которую будет выполнять служба переднего плана. Каждому типу службы переднего плана соответствует соответствующий тип разрешения. Например, если приложение запускает службу переднего плана, использующую камеру, необходимо запросить разрешения FOREGROUND_SERVICE и FOREGROUND_SERVICE_CAMERA . Это все обычные разрешения, поэтому система предоставляет их автоматически, если они указаны в манифесте.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>

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

    <application ...>
        ...
    </application>
</manifest>

Предварительные условия службы переднего плана

Начиная с Android 14 (уровень API 34), при запуске службы переднего плана система проверяет наличие определенных предварительных условий в зависимости от типа службы. Например, если вы попытаетесь запустить приоритетную службу типа location , система проверит, имеет ли ваше приложение разрешение ACCESS_COARSE_LOCATION или ACCESS_FINE_LOCATION . Если этого не происходит, система выдает SecurityException .

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

Запуск службы переднего плана

Прежде чем вы запросите систему для запуска службы в качестве службы переднего плана, запустите саму службу:

Котлин

val intent = Intent(...) // Build the intent for the service
context.startForegroundService(intent)

Ява

Context context = getApplicationContext();
Intent intent = new Intent(...); // Build the intent for the service
context.startForegroundService(intent);

Внутри службы, обычно в onStartCommand() , вы можете запросить запуск службы на переднем плане. Для этого вызовите ServiceCompat.startForeground() (доступно в androidx-core 1.12 и выше). Этот метод принимает следующие параметры:

  • Сервис
  • Положительное целое число, которое однозначно идентифицирует уведомление в строке состояния.
  • Сам объект Notification
  • Типы служб переднего плана , определяющие работу, выполняемую службой.

Эти типы могут быть подмножеством типов, объявленных в манифесте , в зависимости от конкретного варианта использования. Затем, если вам нужно добавить дополнительные типы служб, вы можете снова вызвать startForeground() .

Например, предположим, что фитнес-приложение запускает службу отслеживания бега, которой всегда нужна информация location , но может потребоваться или не потребоваться воспроизведение мультимедиа. Вам нужно будет объявить location и mediaPlayback в манифесте. Если пользователь начинает прогон и просто хочет отслеживать свое местоположение, ваше приложение должно вызвать startForeground() и передать только разрешение ACCESS_FINE_LOCATION . Затем, если пользователь хочет начать воспроизведение звука, снова вызовите startForeground() и передайте побитовую комбинацию всех типов служб переднего плана (в данном случае ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK ).

Вот пример запуска службы переднего плана камеры:

Котлин

class MyCameraService: Service() {

  private fun startForeground() {
    // Before starting the service as foreground check that the app has the
    // appropriate runtime permissions. In this case, verify that the user has
    // granted the CAMERA permission.
    val cameraPermission =
            PermissionChecker.checkSelfPermission(this, Manifest.permission.CAMERA)
    if (cameraPermission != PermissionChecker.PERMISSION_GRANTED) {
        // Without camera permissions the service cannot run in the foreground
        // Consider informing user or updating your app UI if visible.
        stopSelf()
        return
    }

    try {
        val notification = NotificationCompat.Builder(this, "CHANNEL_ID")
            // Create the notification to display while the service is running
            .build()
        ServiceCompat.startForeground(
            /* service = */ this,
            /* id = */ 100, // Cannot be 0
            /* notification = */ notification,
            /* foregroundServiceType = */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
            } else {
                0
            },
        )
    } catch (e: Exception) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
                && e is ForegroundServiceStartNotAllowedException) {
            // App not in a valid state to start foreground service
            // (e.g. started from bg)
        }
        // ...
    }
  }
}

Ява

public class MyCameraService extends Service {

    private void startForeground() {
        // Before starting the service as foreground check that the app has the
        // appropriate runtime permissions. In this case, verify that the user
        // has granted the CAMERA permission.
        int cameraPermission =
            ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (cameraPermission == PackageManager.PERMISSION_DENIED) {
            // Without camera permissions the service cannot run in the
            // foreground. Consider informing user or updating your app UI if
            // visible.
            stopSelf();
            return;
        }

        try {
            Notification notification =
                new NotificationCompat.Builder(this, "CHANNEL_ID")
                    // Create the notification to display while the service
                    // is running
                    .build();
            int type = 0;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                type = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
            }
            ServiceCompat.startForeground(
                    /* service = */ this,
                    /* id = */ 100, // Cannot be 0
                    /* notification = */ notification,
                    /* foregroundServiceType = */ type
            );
        } catch (Exception e) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
                    e instanceof ForegroundServiceStartNotAllowedException
            ) {
                // App not in a valid state to start foreground service
                // (e.g started from bg)
            }
            // ...
        }
    }

    //...
}

Удаление службы с переднего плана

Чтобы удалить службу с переднего плана, вызовите stopForeground() . Этот метод принимает логическое значение, которое указывает, следует ли также удалить уведомление в строке состояния. Обратите внимание, что служба продолжает работать.

Если вы остановите службу, пока она работает на переднем плане, ее уведомление будет удалено.

Обрабатывать инициируемую пользователем остановку приложений, запускающих службы переднего плана.

В нижней части панели уведомлений находится кнопка, которая указывает количество приложений, которые в данный момент работают в фоновом режиме. При нажатии этой кнопки появляется диалоговое окно, в котором перечислены названия различных приложений. Кнопка «Стоп» находится справа от каждого приложения.
Рисунок 1. Рабочий процесс диспетчера задач на устройствах под управлением Android 13 или более поздней версии.

Начиная с Android 13 (уровень API 33), пользователи могут выполнить рабочий процесс из панели уведомлений , чтобы остановить приложение, в котором есть текущие службы переднего плана, независимо от целевой версии SDK этого приложения. Эта возможность, называемая «Диспетчер задач» , показывает список приложений, в которых в данный момент запущена служба переднего плана.

Этот список помечен как «Активные приложения» . Рядом с каждым приложением есть кнопка «Стоп» . На рис. 1 показан рабочий процесс диспетчера задач на устройстве под управлением Android 13.

Когда пользователь нажимает кнопку «Стоп » рядом с вашим приложением в диспетчере задач, происходят следующие действия:

  • Система удалит ваше приложение из памяти. Таким образом, останавливается все ваше приложение , а не только работающая служба переднего плана.
  • Система удаляет стек активности вашего приложения.
  • Любое воспроизведение мультимедиа останавливается.
  • Уведомление, связанное со службой переднего плана, удаляется.
  • Ваше приложение останется в истории.
  • Запланированные задания выполняются в запланированное время.
  • Будильник сработает в запланированное время или временное окно.

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

adb shell cmd activity stop-app PACKAGE_NAME

Исключения

Система предоставляет несколько уровней исключений для определенных типов приложений, которые описаны в следующих разделах.

Исключения предоставляются для каждого приложения, а не для каждого процесса. Если система освобождает один процесс в приложении, все остальные процессы в этом приложении также освобождаются.

Исключения из появления в Диспетчере задач вообще

Следующие приложения могут запускать службу переднего плана и вообще не отображаться в диспетчере задач:

Исключения из запрета на остановку пользователями

Когда следующие типы приложений запускают службу переднего плана, они отображаются в диспетчере задач, но рядом с именем приложения нет кнопки «Стоп» , которую пользователь мог бы нажать:

Используйте специально созданные API вместо служб переднего плана.

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

В документации по типам служб переднего плана перечислены хорошие альтернативы для использования вместо служб переднего плана.

Ограничения на запуск службы переднего плана из фона

Приложения, предназначенные для Android 12 или более поздней версии, не могут запускать службы переднего плана, пока приложение работает в фоновом режиме, за исключением нескольких особых случаев . Если приложение пытается запустить службу переднего плана, пока приложение работает в фоновом режиме, и служба переднего плана не удовлетворяет одному из исключительных случаев, система выдает ForegroundServiceStartNotAllowedException .

Кроме того, если приложение хочет запустить приоритетную службу, которой требуются разрешения во время использования (например, разрешения для датчика тела, камеры, микрофона или местоположения), оно не может создать службу, пока приложение находится в фоновом режиме, даже если приложение попадает в одно из исключений из ограничений на фоновый запуск. Причина этого объясняется в разделе Ограничения на запуск служб переднего плана, которым требуются разрешения во время использования .

Исключения из ограничений фонового запуска

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

Ограничения на запуск служб переднего плана, которым требуются разрешения во время использования.

В Android 14 (уровень API 34) или более поздних версиях существуют особые ситуации, о которых следует знать, если вы запускаете службу переднего плана, которой требуются разрешения во время использования.

Если ваше приложение предназначено для Android 14 или более поздней версии, операционная система проверяет, когда вы создаете службу переднего плана, чтобы убедиться, что у вашего приложения есть все соответствующие разрешения для этого типа службы. Например, когда вы создаете службу переднего плана типа микрофон , операционная система проверяет, имеет ли ваше приложение в настоящее время разрешение RECORD_AUDIO . Если у вас нет такого разрешения, система выдает SecurityException .

Для разрешений во время использования это вызывает потенциальную проблему. Если у вашего приложения есть разрешение на использование, оно будет действовать только тогда, когда оно находится на переднем плане . Это означает, что если ваше приложение работает в фоновом режиме и пытается создать службу переднего плана типа камеры, местоположения или микрофона, система видит, что у вашего приложения в настоящее время нет необходимых разрешений, и выдает SecurityException .

Аналогично, если ваше приложение работает в фоновом режиме и создает службу работоспособности, которой требуется разрешение BODY_SENSORS_BACKGROUND , у приложения в настоящее время нет этого разрешения, и система выдает исключение. (Это неприменимо, если это служба работоспособности, которой требуются другие разрешения, например ACTIVITY_RECOGNITION .) Вызов PermissionChecker.checkSelfPermission() не предотвращает эту проблему. Если у вашего приложения есть разрешение на использование во время использования и оно вызывает checkSelfPermission() , чтобы проверить, есть ли у него такое разрешение, метод возвращает PERMISSION_GRANTED даже если приложение находится в фоновом режиме. Когда метод возвращает PERMISSION_GRANTED , он говорит: «Ваше приложение имеет это разрешение , пока оно используется ».

По этой причине, если вашей службе переднего плана требуется разрешение на использование, вы должны вызвать Context.startForegroundService() или Context.bindService() пока ваше приложение имеет видимую активность, если только служба не попадает в одно из определенных исключений .

Исключения из ограничений на разрешения во время использования

В некоторых ситуациях, даже если служба переднего плана запускается, когда приложение работает в фоновом режиме , она все равно может получить доступ к информации о местоположении, камере и микрофоне, пока приложение работает на переднем плане («во время использования»).

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

Следующий список содержит эти ситуации:

  • Системный компонент запускает службу.
  • Служба начинается с взаимодействия с виджетами приложения .
  • Служба начинается с взаимодействия с уведомлением.
  • Служба запускается как PendingIntent , который отправляется из другого видимого приложения.
  • Служба запускается приложением, которое является контроллером политики устройства и работает в режиме владельца устройства.
  • Служба запускается приложением, которое предоставляет VoiceInteractionService .
  • Служба запускается приложением, имеющим привилегированное разрешение START_ACTIVITIES_FROM_BACKGROUND .
Определите, какие службы в вашем приложении затронуты.

При тестировании приложения запустите его службы переднего плана. Если запущенная служба ограничила доступ к местоположению, микрофону и камере, в Logcat появится следующее сообщение:

Foreground service started from background can not have \
location/camera/microphone access: service SERVICE_NAME