Android

서비스 (1) : 포그라운드 및 백그라운드 서비스

까망사과 2022. 8. 27. 00:00

서비스

서비스는 사용자가 앱과 상호작용 중이지 않을 때도 백그라운드에서 작업을 수행하기 위해 사용하는 앱 컴포넌트다.

액티비티와 달리 UI를 제공하지 않는다.

 


서비스 선언하기

서비스는 Service 클래스를 직접 구현하거나 프레임워크에서 제공하는 하위 클래스를 사용한다.

 

매니페스트 파일에 선언하기

다음처럼 <application>의 하위 태그로 <service>를 선언한다.

<manifest ... >
    ...
    <application ... >
        <service android:name=".ExampleService" />
        ...
    </application>
</manifest>

 

필수 속성인 android:name 속성은 서비스 클래스의 이름을 의미한다. 이외에도 서비스를 실행하는데 필요한 권한, 실행되어야 하는 프로세스 등 여러 속성이 있다.

 

서비스를 앱 내에서만 사용하려면 android:exported 속성을 false로 설정하여 외부 앱의 접근을 방지할 수 있다(명시적 인텐트를 사용해도 실행되지 않는다).

 

android:description 속성을 사용하면 사용자가 확인할 수 있는 서비스 설명문을 설정할 수 있다.

 

서비스의 콜백 메서드

Service 클래스를 구현할 때 몇 가지 중요한 콜백 메서드를 재정의해야 한다.

  • onCreate(): Unit
    서비스 인스턴스가 생성될 때 가장 먼저 호출되는 콜백 메서드. 서비스가 이미 실행 중이라면 호출되지 않는다. 초기 설정 로직을 작성할 수 있다.
  • onStartCommand(Intent, Int, Int): Int
    클라이언트(다른 앱 컴포넌트)가 startService()를 호출하여 서비스를 시작할 때 호출되는 콜백 메서드. 이 메서드가 실행되면 서비스는 무기한으로 실행되기 때문에, 작업을 마쳤다면 stopSelf()를 호출하여 스스로 중지하거나 클라이언트에서 stopService()를 호출하여 중지해야 한다. 서비스가 바인딩만 허용할 경우 이 메서드는 구현하지 않아도 된다.
  • onBind(Intent): IBinder?
    클라이언트가 bindService()를 호출하여 서비스에 바인딩할 때 호출되는 콜백 메서드. 반환하는 IBinder는 클라이언트와 서비스가 상호작용할 때 사용하는 인터페이스다. 서비스가 바인딩을 허용하지 않을 경우 null을 반환해야 한다.
  • onDestroy(): Unit
    서비스가 소멸할 때 호출되는 콜백 메서드. 생성했던 스레드나 리스너 등 남은 리소스를 정리하는 로직을 작성할 수 있다.

 


포그라운드 서비스

사용자가 확인할 수 있도록 알림을 표시하는 서비스를 말한다.

 

Android 버전별 포그라운드 서비스 알림 동작

알림 해제하기

API 레벨 33 이상 버전에서는 포그라운드 서비스 알림을 해제할 수 있다. 이전 버전에서는 서비스가 중지되거나 포그라운드에서 제외되지 않으면 해제할 수 없었다. 물론 알림을 빌드할 때 Notification.Builder.setOngoing()true를 전달하여 이전처럼 해제하지 못하도록 설정할 수도 있다.

 

알림 표시 지연

API 레벨 31 이상 버전에서는 포그라운드 서비스 알림이 10초 동안 지연된 다음 표시된다. 하지만 다음과 같은 경우에는 즉시 표시된다.

  • 알림이 액션 버튼을 포함한다.
  • 포그라운드 서비스 유형이 mediaPlayback, mediaProjection, phoneCall이다.
  • 알림을 빌드할 때 Notification.Builder.setForegroundServiceBehavior(Int)Notification.FOREGROUND_SERVICE_IMMEDIATE를 전달한다.

 

알림 권한

API 레벨 33 이상 버전에서 알림 권한이 승인되지 않으면 알림이 포그라운드 서비스 태스크 매니저에는 표시되지만 알림 창에는 표시되지 않는다.

 

포그라운드 서비스 권한

API 레벨 28 이상 버전에서 포그라운드 서비스를 사용하려면 FOREGROUND_SERVICE 권한이 필요하다. 이는 일반 권한이므로 요청하면 자동으로 승인된다.

 

포그라운드 서비스 시작하기

서비스를 시작하는 인텐트를 준비한다. 이 인텐트를 컴포넌트의 startForegroundService(Intent)에 전달한다. startService()를 사용하여 서비스를 시작할 수 있지만 startForegroundService()는 5초 이내에 서비스에서  startForeground()를 호출할 것이라고 약속된 상황일 때 사용한다.

val intent = Intent( ... )	// 서비스를 시작하는 인텐트
applicationContext.startForegroundService(intent)

 

그러고 나서 서비스에서 startForeground()를 호출하여 서비스가 포그라운드에서 실행되도록 시스템에 요청한다.

  • startForeground(id: Int, notification: Notification): Unit
    * added in API lvl 5

    파라미터 타입 설명
    id Int 표시할 포그라운드 서비스 알림의 ID.
    notification Notification 표시할 포그라운드 서비스 알림.

  • startForeground(id: Int, notification: Notification, foregroundServiceType: Int): Unit
    * added in API lvl 29

    파라미터 타입 설명
    foregroundServiceType Int 포그라운드 서비스 유형을 나타내는 정수형 플래그.
    ServiceInfo.FOREGROUND_SERVICE_TYPE_* 상수를 조합하여 사용한다.

 

백그라운드에서 포그라운드 서비스 시작 제한

API 레벨 31 이상 버전을 타겟팅하는 앱이 백그라운드에서 실행 중일 때 몇 가지 예외를 제외하고 포그라운드 서비스를 시작할 수 없다.

 

포그라운드에서 포그라운드 서비스 제외하기

포그라운드에서 포그라운드 서비스를 제외하려면 서비스에서 stopForeground()를 호출하면 된다. 이 메서드를 호출해도 서비스가 중지되지는 않고 포그라운드에서만 제외될 뿐이다. 서비스가 포그라운드에서 제외되면 메모리가 부족할 때 시스템이 중지할 수 있다.

  • stopForeground(notificationBehavior: Int): Unit
    * added in API lvl 24
    서비스를 포그라운드 상태에서 제거한다.

    파라미터 타입 설명
    notificationBehavior Int 제거할 서비스의 알림의 동작 방식을 의미한다. 아래 나열된 Service 클래스의 상수를 사용할 수 있다.
    • STOP_FOREGROUND_REMOVE
      서비스의 알림이 즉시 해제된다.
    • STOP_FOREGROUND_DETACH
      서비스와 알림의 연결이 해제된다. 알림 지연 정책(시스템이 10초 동안 대기했다가 알림을 표시)으로 인해 아직 알림이 표시되지 않았을 때 stopForeground()이 호출되었다면 알림이 즉시 표시된다. 알림은 서비스가 완전히 중지되고 소멸된 후에도 표시되어 있다.
  • stopForeground(removeNotification: Boolean): Unit
    * added in API lvl 5 / deprecated in API lvl 33

    파라미터 타입 설명
    removeNotification Boolean 포그라운드에서 제거할 서비스의 알림을 해제할지 여부를 의미한다. true를 전달하면 stopForeground(Int) Service.STOP_FOREGROUND_REMOVE가 전달되고 그렇지 않으면 STOP_FOREGROUND_LEGACY가 전달된다.

 

포그라운드 서비스를 실행 중인 앱 종료하기

API 레벨 33 이상 버전을 실행하는 디바이스는 알림 창에서 포그라운드 서비스 태스크 매니저를 통해 포그라운드 서비스를 실행 중인 앱을 종료할 수 있다. 그렇게 하면 다음 동작이 발생한다.

  • 시스템이 메모리에서 앱을 제거한다. 따라서 포그라운드 서비스뿐 아니라 앱 자체가 종료된다.
  • 앱의 액티비티가 백스택에서 제거된다.
  • 미디어 재생이 중지된다.
  • 앱이 히스토리에서 제거되지는 않는다.
  • 예약된 작업 및 알람은 보존된다.

 

포그라운드 서비스 유형 설정하기

포그라운드 서비스 유형을 설정하려면 <service>android:foregroundServiceType 속성을 사용한다. 한 서비스에 여러 값을 동시에 설정할 수 있으며 설정할 수 있는 값은 다음과 같다.

  • "camera"
    카메라 액세스.
  • "connectedDevice"
    자동차, TV, 블루투스 등 다른 기기와의 연결을 모니터링 및 상호작용.
  • "dataSync"
    데이터(사진, 파일, 계정 등)의 업로드 및 다운로드, 가져오기 및 내보내기, 디바이스와 클라우드 사이 네트워크를 통한 전송.
  • "location"
    위치 정보 액세스.
  • "mediaPlayback"
    음악, 동영상, 뉴스 또는 기타 미디어 재생.
  • "mediaProjection"
    스크린샷 촬영, 화면 녹화와 같은 미디어 프로젝션 세션 관리.
  • "microphone"
    마이크에 액세스.
  • "phoneCall"
    통화, 화상 회의, 또는 이와 유사한 상호작용 통신과 관련된 지속적인 작업.

 

액세스 제한

API 레벨 30 이상 버전에서 앱이 백그라운드에서 실행되고 있을 때 포그라운드 서비스를 시작하면 서비스는 카메라 및 마이크에 액세스할 수 없다. 또한 백그라운드 위치 권한(ACCESS_BACKGROUND_LOCATION)이 없으면 서비스는 위치 정보에 액세스할 수 없다.

 

포그라운드 서비스 유형 필터링

서비스에서 startForeground()를 호출하면 매니페스트에 선언된 포그라운드 서비스 유형에 대한 액세스가 허용된다. 허용된 유형 중에서 일부분만 필요하다면 다음처럼 startForeground()에 플래그를 전달하여 필요한 포그라운드 서비스 유형을 필터링할 수 있다.

val notification: Notification = ...;
startForeground(
    NOTIFICATION_ID,
    notification,
    ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA or
            ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
)

 

플래그로 사용할 수 있는 값은 ServiceInfo 클래스의 FOREGROUND_SERVICE_TYPE_* 상수다.

  • FOREGROUND_SERVICE_TYPE_MANIFEST
    매니페스트 파일에 선언된 모든 유형을 그대로 사용.
  • FOREGROUND_SERVICE_TYPE_NONE
    매니페스트 파일에 선언되지 않은 경우 기본 포그라운드 서비스 유형을 사용.
  • FOREGROUND_SERVICE_TYPE_CAMERA
    "camera"에 대응.
  • FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE
    "connectedDevice"에 대응.
  • FOREGROUND_SERVICE_TYPE_DATA_SYNC
    "dataSync"에 대응.
  • FOREGROUND_SERVICE_TYPE_LOCATION
    "location"에 대응.
  • FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
    "mediaPlayback"에 대응.
  • FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
    "mediaProjection"에 대응.
  • FOREGROUND_SERVICE_TYPE_MICROPHONE
    "microphone"에 대응.
  • FOREGROUND_SERVICE_TYPE_PHONE_CALL
    "phoneCall"에 대응.

 


백그라운드 서비스

사용자에게 직접적으로 보이지 않는 작업을 수행하는 서비스.

 

백그라운드 서비스 제한

API 레벨 26 이상 버전을 타겟팅하는 앱이 포그라운드에 있지 않으면 백그라운드 서비스 실행이 제한된다.

 

다음과 같은 경우 앱이 포그라운드에 있는 것으로 간주된다.

  • 상태가 "시작됨"이든 "일시중지됨"이든 눈에 보이는 액티비티가 있다.
  • 포그라운드 서비스가 있다.
  • 포그라운드에 있는 다른 앱과 연결(다른 앱의 서비스에 바인딩되어 있거나 컨텐츠 프로바이더를 사용)되어 있다.

위에 하나도 해당하지 않는 경우 앱이 백그라운드에 있는 것으로 간주된다.

 

앱이 포그라운드에 있는 동안 포그라운드 및 백그라운드 서비스를 자유롭게 생성하고 실행할 수 있다. 앱이 백그라운드로 이동해도 몇 분 동안은 서비스를 생성하고 사용할 수 있다. 그 뒤에는 앱이 유휴 상태로 간주된다. 이 때 시스템이 앱의 백그라운드 서비스를 중지한다.

 

하지만 백그라운드에 있는 앱이 자유롭게 서비스를 시작하고 백그라운드 서비스를 실행할 수 있다. 앱이 사용자에게 보이는 작업을 처리할 때 이것이 가능해진다.

'Android' 카테고리의 다른 글

서비스 (3) : 시작되는 서비스  (0) 2022.08.29
서비스 (2) : 바인딩된 서비스  (0) 2022.08.28
액션 바 사용하기  (0) 2022.08.09
알림 표시하기  (0) 2022.07.26
진동 울리기  (0) 2022.07.21