Запустить службу переднего плана,Запустить службу переднего плана

Запуск службы переднего плана из вашего приложения состоит из двух шагов. Во-первых, вы должны запустить службу, вызвав context.startForegroundService() . Затем вызовите службу ServiceCompat.startForeground() чтобы превратить ее в службу переднего плана.

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

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

  • Приложениям, предназначенным для Android 12 (уровень API 31) или выше, не разрешается запускать службу переднего плана, пока приложение находится в фоновом режиме, за некоторыми особыми исключениями. Дополнительные сведения и сведения об исключениях из этого правила см. в разделе Ограничения на запуск службы переднего плана из фонового режима .

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

Запустить сервис

Чтобы запустить службу переднего плана, вы должны сначала запустить ее как обычную (не переднюю) службу:

Котлин

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

Ключевые моменты о коде

  • Фрагмент кода запускает службу. Однако служба еще не работает на переднем плане. Внутри самой службы вам необходимо вызвать 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 ).

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

Котлин

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)
            }
            // ...
        }
    }

    //...
}

Ключевые моменты о коде

  • Приложение уже заявило в манифесте, что ему требуется разрешение CAMERA . Однако приложение также должно проверять во время выполнения, чтобы убедиться, что пользователь предоставил это разрешение. Если приложение на самом деле не имеет правильных разрешений, оно должно сообщить пользователю о проблеме.
  • Различные типы служб переднего плана были представлены в разных версиях платформы Android. Этот код проверяет, на какой версии Android он работает, и запрашивает соответствующие разрешения.
  • Код проверяет наличие ForegroundServiceStartNotAllowedException в случае, если он пытается запустить службу переднего плана в ситуации, которая не разрешена (например, если он пытается перевести службу на передний план , когда приложение находится в фоновом режиме ).