Чтобы запустить активную службу из приложения, нужно выполнить два шага. Сначала запустите службу, вызвав context.startForegroundService(). Затем служба должна вызвать метод ServiceCompat.startForeground(), чтобы стать активной службой.
Требования
В зависимости от того, на какой уровень API ориентировано ваше приложение, существуют некоторые ограничения на то, когда приложение может запустить активную службу.
Приложения, предназначенные для Android 12 (уровень API 31) или более поздней версии, не могут запускать активные службы, когда работают в фоновом режиме. Из этого правила есть несколько исключений. Подробнее об этом и исключениях из правила читайте в статье Ограничения на запуск активной службы из фонового режима.
Приложения, предназначенные для Android 14 (уровень API 34) или более поздней версии, должны запрашивать подходящие разрешения для типа активной службы. Когда приложение пытается перевести службу в активный режим, система проверяет наличие необходимых разрешений и, если их нет, выдает ошибку
SecurityException. Например, если вы попытаетесь запустить активную службу типаlocation, система проверит, есть ли у приложения разрешениеACCESS_COARSE_LOCATIONилиACCESS_FINE_LOCATION. Необходимые условия для каждого типа активной службы перечислены в документации.
Запуск сервиса
Чтобы запустить активную службу, сначала запустите ее как обычную (неактивную) службу:
Kotlin
val intent = Intent(...) // Build the intent for the service context.startForegroundService(intent)
Java
Context context = getApplicationContext(); Intent intent = new Intent(...); // Build the intent for the service context.startForegroundService(intent);
Важные сведения о коде
- Фрагмент кода запускает сервис. Однако служба ещё не запущена в активном режиме. Внутри самой службы необходимо вызвать
ServiceCompat.startForeground(), чтобы сделать ее активной.
Как перевести службу в активный режим
После запуска службы необходимо вызвать ServiceCompat.startForeground(), чтобы запросить ее запуск в активном режиме. Обычно этот метод вызывается в методе onStartCommand() сервиса.
ServiceCompat.startForeground() принимает следующие параметры:
- Сервис.
- Положительное целое число, которое уникальным образом идентифицирует уведомление сервиса в строке состояния.
- Сам объект
Notification. - Тип или типы активных служб, определяющие выполняемую ими работу.
Типы активных служб, которые вы передаете методу startForeground(), должны соответствовать типам, объявленным в манифесте, в зависимости от конкретного варианта использования. Если вам нужно добавить другие типы услуг, вы можете снова вызвать startForeground().
Например, в фитнес-приложении есть служба отслеживания бега, которой всегда нужны данные location, но не всегда требуется воспроизводить медиаконтент. В манифесте нужно объявить оба разрешения: location и mediaPlayback. Если пользователь начинает пробежку и хочет, чтобы отслеживалось только его местоположение, приложение должно вызвать startForeground() и передать только разрешение ACCESS_FINE_LOCATION. Если пользователь захочет включить аудио, снова вызовите startForeground() и передайте побитовую комбинацию всех типов активных служб (в этом случае – ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK).
В примере ниже показан код, который служба камеры использует для перехода в активную службу.
Kotlin
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) } // ... } } }
Java
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) } // ... } } //... }
Важные сведения о коде
- В манифесте приложения уже указано, что ему требуется разрешение
CAMERA. Однако приложение также должно проверять во время выполнения, предоставил ли пользователь это разрешение. Если у приложения нет нужных разрешений, оно должно сообщить об этом пользователю. - Разные типы активных служб были представлены в разных версиях платформы Android. Этот код проверяет версию Android, на которой он выполняется, и запрашивает соответствующие разрешения.
- Код проверяет наличие
ForegroundServiceStartNotAllowedExceptionна случай, если он пытается запустить активную службу в недопустимой ситуации (например, если он пытается перевести службу в активный режим, пока приложение находится в фоновом режиме).