포그라운드 서비스는 사용자에게 잘 보이는 작업을 실행합니다.
포그라운드 서비스는 상태 표시줄 알림을 표시하여 앱이 포그라운드에서 작업을 실행하고 시스템 리소스를 소비하고 있다는 사실을 사용자에게 알립니다.
포그라운드 서비스를 사용하는 앱의 예는 다음과 같습니다.
- 포그라운드 서비스에서 음악을 재생하는 음악 플레이어 앱 알림에 현재 재생 중인 곡이 표시될 수 있습니다.
- 사용자로부터 권한을 받은 후 포그라운드 서비스에서 사용자의 달리기를 기록하는 피트니스 앱 알림에는 사용자가 현재 피트니스 세션 중에 이동한 거리가 표시될 수 있습니다.
포그라운드 서비스는 앱이 사용자가 앱과 직접 상호작용을 주고받지 않더라도 사용자가 인지할 수 있는 작업을 수행해야 하는 경우에만 사용해야 합니다. 작업의 중요도가 낮아서 최소한의 우선순위 알림을 사용하고자 하는 경우에는 대신 백그라운드 작업을 만드세요.
이 문서에서는 포그라운드 서비스를 사용하는 데 필요한 권한과 포그라운드 서비스를 시작하고 백그라운드에서 삭제하는 방법을 설명합니다. 또한 특정 사용 사례를 포그라운드 서비스 유형과 연결하는 방법과 백그라운드에서 실행 중인 앱에서 포그라운드 서비스를 시작할 때 적용되는 액세스 제한에 관해 설명합니다.
사용자는 기본적으로 알림을 닫을 수 있습니다.
Android 13 (API 수준 33)부터 사용자는 기본적으로 포그라운드 서비스와 연결된 알림을 닫을 수 있습니다. 이를 위해 사용자는 알림에서 스와이프 동작을 실행합니다. 기존에는 포그라운드 서비스가 중지되거나 포그라운드에서 삭제되지 않는 한 알림이 해제되지 않았습니다.
사용자가 알림을 닫을 수 없도록 하려면 Notification.Builder
를 사용하여 알림을 만들 때 true
를 setOngoing()
메서드에 전달합니다.
알림을 즉시 표시하는 서비스
포그라운드 서비스에 다음 특성 중 하나 이상이 있으면 시스템에서는 Android 12 이상을 실행하는 기기에서도 서비스가 시작된 직후 연결된 알림을 표시합니다.
- 서비스가 작업 버튼이 포함된 알림과 연결됩니다.
- 서비스에
mediaPlayback
,mediaProjection
또는phoneCall
의foregroundServiceType
이 있습니다. - 서비스는 알림의 카테고리 속성에 정의된 전화 통화, 탐색 또는 미디어 재생과 관련된 사용 사례를 제공합니다.
- 이 서비스는 알림을 설정할 때
FOREGROUND_SERVICE_IMMEDIATE
를setForegroundServiceBehavior()
로 전달하여 동작 변경사항을 선택 해제했습니다.
Android 13 (API 수준 33) 이상에서 사용자가 알림 권한을 거부하더라도 작업 관리자에서는 포그라운드 서비스와 관련된 알림을 계속 볼 수 있지만 알림 창에는 표시되지 않습니다.
매니페스트에서 포그라운드 서비스 선언
앱 매니페스트에서 <service>
요소를 사용하여 앱의 각 포그라운드 서비스를 선언합니다. 각 서비스에 android:foregroundServiceType
속성을 사용하여 서비스가 하는 작업의 종류를 선언합니다.
예를 들어 앱에서 음악을 재생하는 포그라운드 서비스를 만드는 경우 다음과 같이 서비스를 선언할 수 있습니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<application ...>
<service
android:name=".MyMediaPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false">
</service>
</application>
</manifest>
서비스에 여러 유형이 적용되는 경우 |
연산자로 구분하세요. 예를 들어 카메라와 마이크를 사용하는 서비스는 다음과 같이 선언합니다.
android:foregroundServiceType="camera|microphone"
포그라운드 서비스 권한 요청하기
Android 9 (API 수준 28) 이상을 타겟팅하고 포그라운드 서비스를 사용하는 앱은 다음 코드 스니펫과 같이 앱 매니페스트에서 FOREGROUND_SERVICE
를 요청해야 합니다. 이는 일반 권한이므로 시스템은 요청 앱에 자동으로 권한을 부여합니다.
또한 앱이 API 수준 34 이상을 타겟팅하는 경우 포그라운드 서비스가 실행할 작업 유형에 적절한 권한 유형을 요청해야 합니다. 각 포그라운드 서비스 유형에는 해당하는 권한 유형이 있습니다. 예를 들어 앱이 카메라를 사용하는 포그라운드 서비스를 실행하는 경우 FOREGROUND_SERVICE
및 FOREGROUND_SERVICE_CAMERA
권한을 모두 요청해야 합니다. 이는 모두 일반 권한이므로 매니페스트에 나열된 경우 시스템에서 자동으로 권한을 부여합니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
<application ...>
...
</application>
</manifest>
포그라운드 서비스 기본 요건
Android 14 (API 수준 34)부터 포그라운드 서비스를 실행할 때 시스템은 서비스 유형에 따라 특정 기본 요건을 확인합니다. 예를 들어 location
유형의 포그라운드 서비스를 실행하려고 하면 시스템은 앱에 이미 ACCESS_COARSE_LOCATION
또는 ACCESS_FINE_LOCATION
권한이 있는지 확인합니다. 그렇지 않으면 시스템에서 SecurityException
을 발생시킵니다.
따라서 포그라운드 서비스를 시작하기 전에 필수 기본 요건이 충족되는지 확인해야 합니다. 포그라운드 서비스 유형 문서에는 각 포그라운드 서비스 유형에 필요한 기본 요건이 나와 있습니다.
포그라운드 서비스 시작
시스템에 서비스를 포그라운드 서비스로 실행하도록 요청하기 전에 서비스 자체를 시작합니다.
Kotlin
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);
서비스 내부(일반적으로 onStartCommand()
)에서 서비스가 포그라운드에서 실행되도록 요청할 수 있습니다. 이렇게 하려면 ServiceCompat.startForeground()
를 호출합니다(androidx-core 1.12 이상에서 사용 가능). 이 메서드에는 다음 매개변수가 사용됩니다.
- 서비스
- 상태 표시줄의 알림을 고유하게 식별하는 양의 정수입니다.
Notification
객체 자체- 서비스에서 실행한 작업을 식별하는 포그라운드 서비스 유형
이러한 유형은 특정 사용 사례에 따라 매니페스트에 선언된 유형의 하위 집합일 수 있습니다. 그런 다음 서비스 유형을 더 추가해야 하는 경우 startForeground()
를 다시 호출할 수 있습니다.
예를 들어 피트니스 앱이 항상 location
정보가 필요하지만 미디어를 재생해야 할 수도 있고 아닐 수도 있는 달리기 추적 서비스를 실행한다고 가정해 보겠습니다. 매니페스트에서 location
와 mediaPlayback
를 모두 선언해야 합니다. 사용자가 달리기를 시작하고 위치만 추적하려는 경우 앱은 startForeground()
를 호출하고 ACCESS_FINE_LOCATION
권한만 전달해야 합니다. 그런 다음 사용자가 오디오 재생을 시작하려는 경우 startForeground()
를 다시 호출하고 모든 포그라운드 서비스 유형 (이 경우 ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK
)의 비트 조합을 전달합니다.
다음은 카메라 포그라운드 서비스를 실행하는 예입니다.
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) } // ... } } }
자바
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) } // ... } } //... }
포그라운드에서 서비스 삭제
서비스를 포그라운드에서 삭제하려면 stopForeground()
를 호출합니다.
이 메서드는 상태 표시줄 알림도 삭제할지 여부를 나타내는 불리언을 사용합니다. 서비스는 계속 실행됩니다.
서비스가 포그라운드에서 실행 중일 때 중지하면 알림이 삭제됩니다.
포그라운드 서비스를 실행하는 앱의 사용자 시작 중지 처리
Android 13 (API 수준 33)부터 사용자는 알림 창에서 워크플로를 완료하여 앱의 타겟 SDK 버전과 관계없이 진행 중인 포그라운드 서비스가 있는 앱을 중지할 수 있습니다. 작업 관리자라고 하는 이 어포던스에는 현재 포그라운드 서비스를 실행 중인 앱 목록이 표시됩니다.
이 목록에는 활성 앱이라는 라벨이 적용되어 있습니다. 각 앱의 옆에는 중지 버튼이 있습니다. 그림 1은 Android 13을 실행하는 기기의 작업 관리자 워크플로를 보여줍니다.
사용자가 작업 관리자에서 앱 옆의 중지 버튼을 누르면 다음 작업이 실행됩니다.
- 시스템이 메모리에서 앱을 삭제합니다. 따라서 실행 중인 포그라운드 서비스뿐만 아니라 앱 전체가 중지됩니다.
- 시스템에서 앱의 활동 백 스택을 삭제합니다.
- 미디어 재생이 중지됩니다.
- 포그라운드 서비스와 연결된 알림이 삭제됩니다.
- 앱은 기록에 남아 있습니다.
- 예약된 작업은 예약된 시간에 실행됩니다.
- 예약된 시간 또는 시간대에 울립니다.
사용자가 앱을 중지하는 동안에 그리고 앱을 중지한 후에 앱이 예상대로 동작하는지 테스트하려면 터미널 창에서 다음 ADB 명령어를 실행하세요.
adb shell cmd activity stop-app PACKAGE_NAME
예외
시스템은 이어지는 섹션에서 설명하는 특정 유형의 앱에 대해 여러 수준의 예외를 제공합니다.
예외는 프로세스가 아닌 앱별로 적용됩니다. 시스템이 하나의 앱에서 하나의 프로세스에 예외를 제공한 경우 이 앱의 다른 모든 프로세스에도 예외가 제공됩니다.
작업 관리자에 전혀 표시되지 않음
다음과 같은 앱은 포그라운드 서비스를 실행해도 작업 관리자에 전혀 표시되지 않습니다.
- 시스템 수준 앱
- 안전 앱(
ROLE_EMERGENCY
역할이 있는 앱) - 데모 모드인 기기
사용자가 중지할 수 없음
다음과 같은 유형의 앱이 포그라운드 서비스를 실행하면 작업 관리자에 표시되기는 하나 앱 옆에 사용자가 탭할 수 있는 중지 버튼이 없습니다.
- 기기 소유자 앱
- 프로필 소유자 앱
- 지속 앱
ROLE_DIALER
역할이 있는 앱
포그라운드 서비스 대신 목적에 맞게 빌드된 API 사용
많은 사용 사례에서 포그라운드 서비스를 사용하는 데 사용할 수 있는 플랫폼 또는 Jetpack API가 있습니다. 적절한 목적 지향 API가 있는 경우 거의 항상 포그라운드 서비스를 사용하는 대신 이를 사용해야 합니다. 목적에 맞게 빌드된 API는 자체적으로 빌드해야 하는 추가 사용 사례별 기능을 제공하는 경우가 많습니다. 예를 들어 Bubbles API는 채팅 풍선 기능을 구현해야 하는 메시지 앱의 복잡한 UI 로직을 처리합니다.
포그라운드 서비스 유형 문서에는 포그라운드 서비스 대신 사용할 수 있는 적절한 대안이 나와 있습니다.
백그라운드에서 포그라운드 서비스를 시작할 때 적용되는 제한사항
Android 12 이상을 타겟팅하는 앱은 몇 가지 특수한 사례를 제외하고 앱이 백그라운드에서 실행되는 동안 포그라운드 서비스를 시작할 수 없습니다. 앱이 백그라운드에서 실행되는 동안 포그라운드 서비스를 시작하려고 하지만 포그라운드 서비스가 예외 사례 중 하나를 충족하지 않으면 시스템에서 ForegroundServiceStartNotAllowedException
이 발생합니다.
또한 앱이 사용 중 권한 (예: 생체 신호 센서, 카메라, 마이크 또는 위치 정보 권한)이 필요한 포그라운드 서비스를 실행하려는 경우 앱이 백그라운드 시작 제한의 예외 중 하나에 해당하더라도 앱이 백그라운드에 있는 동안에는 서비스를 만들 수 없습니다. 그 이유는 사용 중 권한이 필요한 포그라운드 서비스 시작에 관한 제한사항 섹션에 설명되어 있습니다.
백그라운드 시작 제한의 예외
다음 상황에서는 앱이 백그라운드에서 실행되는 동안에도 포그라운드 서비스를 시작할 수 있습니다.
- 앱이 활동과 같은 사용자에게 표시되는 상태에서 전환됩니다.
- 앱은 백그라운드에서 활동을 시작할 수 있습니다. 단, 앱이 기존 작업의 백 스택에 활동을 보유한 경우는 예외입니다.
앱이 Firebase 클라우드 메시징을 사용하여 우선순위가 높은 메시지를 수신합니다.
사용자가 앱과 관련된 UI 요소에서 작업을 실행합니다. 예를 들어 대화창이나 알림, 위젯, 활동과 상호작용할 수 있습니다.
앱이 정확한 알람을 호출하여 사용자가 요청한 작업을 완료합니다.
앱이 기기의 현재 입력 메서드입니다.
기기가 재부팅되고 broadcast receiver에서
ACTION_BOOT_COMPLETED
나ACTION_LOCKED_BOOT_COMPLETED
,ACTION_MY_PACKAGE_REPLACED
인텐트 작업을 수신한 후의 경우입니다.앱이 broadcast receiver에서
ACTION_TIMEZONE_CHANGED
나ACTION_TIME_CHANGED
,ACTION_LOCALE_CHANGED
인텐트 작업을 수신합니다.앱이
NfcService
에서ACTION_TRANSACTION_DETECTED
이벤트를 수신합니다.앱에서 호환 기기 관리도구를 사용하고
REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
권한 또는REQUEST_COMPANION_RUN_IN_BACKGROUND
권한을 선언합니다. 가능하면REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
를 사용하세요.사용자가 앱의 배터리 최적화를 사용 중지합니다.
앱에
SYSTEM_ALERT_WINDOW
권한이 있습니다. 참고: 앱이 Android 15 이상을 타겟팅하는 경우SYSTEM_ALERT_WINDOW
권한이 있어야 하며 앱에 현재 표시되는 오버레이 창이 있어야 합니다.
사용 중 권한이 필요한 포그라운드 서비스 시작 제한
Android 14 (API 수준 34) 이상에서는 사용 중 권한이 필요한 포그라운드 서비스를 시작할 때 유의해야 할 특별한 상황이 있습니다.
앱이 Android 14 이상을 타겟팅하는 경우 포그라운드 서비스를 만들 때 운영체제가 앱에 해당 서비스 유형에 적합한 모든 권한이 있는지 확인합니다. 예를 들어 마이크 유형의 포그라운드 서비스를 만들면 운영체제는 앱에 현재 RECORD_AUDIO
권한이 있는지 확인합니다. 이 권한이 없으면 시스템에서 SecurityException
이 발생합니다.
사용 중 권한의 경우 이로 인해 문제가 발생할 수 있습니다. 앱에 사용 중 권한이 있는 경우 포그라운드에 있는 동안에만 이 권한을 가집니다. 즉, 앱이 백그라운드에 있고 앱이 카메라, 위치 또는 마이크 유형의 포그라운드 서비스를 만들려고 하면 시스템은 앱에 현재 필요한 권한이 없음을 확인하고 SecurityException
을 발생시킵니다.
마찬가지로 앱이 백그라운드에 있고 BODY_SENSORS
권한이 필요한 건강 서비스를 만드는 경우 앱에 현재 해당 권한이 없으므로 시스템에서 예외가 발생합니다.
(ACTIVITY_RECOGNITION
와 같이 다른 권한이 필요한 건강 관리 서비스인 경우에는 적용되지 않습니다.) PermissionChecker.checkSelfPermission()
를 호출해도 이 문제가 방지되지 않습니다. 앱에 사용 중 권한이 있고 checkSelfPermission()
를 호출하여 이 권한이 있는지 확인하는 경우 앱이 백그라운드에 있더라도 메서드는 PERMISSION_GRANTED
을 반환합니다. 메서드가 PERMISSION_GRANTED
를 반환하면 '앱이 사용 중일 때 앱에 이 권한이 있습니다.'라고 표시됩니다.
따라서 포그라운드 서비스에 사용 중 권한이 필요한 경우 서비스가 정의된 예외 중 하나에 해당하지 않는 한 앱에 표시되는 활동이 있는 동안 Context.startForegroundService()
또는 Context.bindService()
를 호출해야 합니다.
사용 중 권한 제한 예외
경우에 따라 앱이 백그라운드에서 실행되는 동안 포그라운드 서비스가 시작되더라도 앱이 포그라운드에서 실행되는 동안('사용 중에만') 위치, 카메라, 마이크 정보에 계속 액세스할 수 있습니다.
이와 동일한 상황에서 서비스가 location
의 포그라운드 서비스 유형을 선언하고 ACCESS_BACKGROUND_LOCATION
권한이 있는 앱에 의해 시작되면 이 서비스는 앱이 백그라운드에서 실행되더라도 항상 위치 정보에 액세스할 수 있습니다.
다음 목록에는 이러한 상황이 포함됩니다.
- 시스템 구성요소가 서비스를 시작합니다.
- 서비스는 앱 위젯과의 상호작용으로 시작됩니다.
- 서비스가 알림과의 상호작용으로 시작됩니다.
- 서비스가 표시된 다른 앱에서 전송된
PendingIntent
로 시작됩니다. - 서비스는 기기 소유자 모드로 실행되는 기기 정책 컨트롤러인 앱에 의해 시작됩니다.
- 서비스가
VoiceInteractionService
를 제공하는 앱에 의해 시작됩니다. - 서비스가
START_ACTIVITIES_FROM_BACKGROUND
권한이 있는 앱에 의해 시작됩니다.
앱에서 영향을 받는 서비스 확인
앱을 테스트할 때 포그라운드 서비스를 시작합니다. 시작된 서비스에 위치, 마이크 및 카메라 액세스 제한이 적용된 경우 다음 메시지가 Logcat에 표시됩니다.
Foreground service started from background can not have \ location/camera/microphone access: service SERVICE_NAME