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