Há duas etapas para iniciar um serviço em primeiro plano no app. Primeiro, é necessário iniciar o serviço chamando
context.startForegroundService()
. Em seguida, faça com que
o serviço chame ServiceCompat.startForeground()
para se promover
em um serviço em primeiro plano.
Pré-requisitos
Dependendo do nível da API que o app tem como destino, há algumas restrições sobre quando um app pode iniciar um serviço em primeiro plano.
Apps direcionados ao Android 12 (nível 31 da API) ou mais recentes não podem iniciar um serviço em primeiro plano enquanto o app está em segundo plano, com algumas exceções específicas. Para mais informações e informações sobre as exceções a essa regra, consulte Restrições para iniciar um serviço em primeiro plano do segundo plano.
Os apps destinados ao Android 14 (nível 34 da API) ou mais recentes precisam solicitar as permissões adequadas para o tipo de serviço em primeiro plano. Quando o app tenta promover um serviço para o primeiro plano, o sistema verifica as permissões adequadas e gera
SecurityException
se o app estiver sem nenhuma. Por exemplo, se você tentar iniciar um serviço em primeiro plano do tipolocation
, o sistema vai verificar se o app já tem a permissãoACCESS_COARSE_LOCATION
ouACCESS_FINE_LOCATION
. A documentação do tipo de serviço em primeiro plano lista os pré-requisitos necessários para cada tipo de serviço em primeiro plano.
Iniciar um serviço
Para iniciar um serviço em primeiro plano, primeiro você precisa iniciá-lo como um serviço comum (não em primeiro plano):
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);
Pontos principais sobre o código
- O snippet de código inicia um serviço. No entanto, o serviço ainda não está
em execução em primeiro plano. No serviço, é necessário chamar
ServiceCompat.startForeground()
para promover o serviço a um serviço em primeiro plano.
Promover um serviço para o primeiro plano
Quando um serviço está em execução, é necessário chamar
ServiceCompat.startForeground()
para solicitar que ele
seja executado em primeiro plano. Normalmente, você chamaria esse método no método
onStartCommand()
do serviço.
ServiceCompat.startForeground()
usa os seguintes parâmetros:
- O serviço.
- Um número inteiro positivo que identifica exclusivamente a notificação do serviço na barra de status.
- O próprio objeto
Notification
. - Os tipos de serviço em primeiro plano que identificam o trabalho realizado pelo serviço
Os tipos de serviço em primeiro plano que você transmite para startForeground()
tipos declarados no manifesto, dependendo do caso de uso
específico. Em seguida, se você precisar adicionar mais tipos de serviço, chame
startForeground()
novamente.
Por exemplo, suponha que um app de condicionamento físico execute um serviço de rastreamento de corrida que sempre
precisa de informações location
, mas pode ou não precisar reproduzir mídia. Você
precisa declarar location
e mediaPlayback
no manifesto. Se um
usuário iniciar uma corrida e quiser apenas que o local seja rastreado, o app precisará chamar
startForeground()
e transmitir apenas a permissão ACCESS_FINE_LOCATION
. Em seguida,
se o usuário quiser começar a reproduzir áudio, chame startForeground()
novamente e
transmita a combinação de bits de todos os tipos de serviço em primeiro plano (neste caso,
ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK
).
O exemplo a seguir mostra o código que um serviço de câmera usaria para se promover a um serviço em primeiro plano:
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) } // ... } } //... }
Pontos principais sobre o código
- O app já declarou no manifesto que precisa da permissão
CAMERA
. No entanto, o app também precisa verificar no momento da execução para garantir que o usuário concedeu essa permissão. Se o app não tiver as permissões corretas, ele precisa informar o problema ao usuário. - Diferentes tipos de serviços em primeiro plano foram introduzidos com diferentes versões da plataforma Android. Esse código verifica em qual versão do Android ele está executando e solicita as permissões adequadas.
- O código verifica
ForegroundServiceStartNotAllowedException
caso ele esteja tentando iniciar um serviço em primeiro plano em uma situação que não é permitida (por exemplo, se ele estiver tentando promover o serviço para o primeiro plano enquanto o app está em segundo plano).