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

Запуск службы переднего плана из вашего приложения состоит из двух шагов. Сначала необходимо запустить службу, вызвав метод 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() принимает следующие параметры:

Типы служб переднего плана, передаваемые методу 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 в случае, если он пытается запустить службу переднего плана в ситуации, которая недопустима (например, если он пытается перевести службу на передний план , пока приложение находится в фоновом режиме ).