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

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

Предпосылки

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

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

  • Apps that target Android 14 (API level 34) or higher must request the appropriate permissions for the foreground service type. When the app attempts to promote a service to the foreground, the system checks for the appropriate permissions and throws throws SecurityException if the app is missing any. For example, if you try to launch a foreground service of type location , the system checks to make sure your app already has either the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission. The foreground service type documentation lists the required prerequisites for each foreground service type.

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

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

Котлин

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() .

For example, suppose a fitness app runs a running-tracker service that always needs location information, but might or might not need to play media. You would need to declare both location and mediaPlayback in the manifest. If a user starts a run and just wants their location tracked, your app should call startForeground() and pass just the ACCESS_FINE_LOCATION permission. Then, if the user wants to start playing audio, call startForeground() again and pass the bitwise combination of all the foreground service types (in this case, 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 в случае, если он пытается запустить службу переднего плана в ситуации, которая недопустима (например, если он пытается перевести службу на передний план, пока приложение находится в фоновом режиме ).