본문 바로가기
Android

[Doit 깡샘의 안드로이드 앱 프로그래밍 with 코틀린] 정리 15 - 서비스의 백그라운드 제약

by 들풀민들레 2022. 2. 28.
본 글은 [Doit 깡샘의 안드로이드 앱 프로그래밍 with 코틀린 - 이지스퍼블리싱 (2022)] 의 내용을 발췌한 것입니다.

좀더 자세한 내용은 책 혹은 인강을 통해 확인해 주세요.

 

 

 

 

서비스는 앱이 백그라운드 상태일 때 인텐트를 전달하면 오류가 발생합니다. 포그라운드 상황에서는 잘 실행되던 인텐트도 백그라운드 상황에서는 다음과 같은 오류가 발생합니다.

 

Not allowed to start service Intent { act=ACTION_OUTER_SERVICE pkg=com.example.test_outter }: app is in background uid null

백그라운드는 앱의 화면이 안 보이는 상황이지만 세부적으로는 몇 가지를 더 고려해야 합니다. 안드로이드 시스템에서 서비스가 정상으로 실행되는 포그라운드 상황은 다음과 같습니다.


• 액티비티가 시작되든 일시 중지되든 상관없이 보이는 액티비티가 있을 때
• 포그라운드 서비스가 있을 때
• 앱의 서비스에 바인딩하거나 앱의 콘텐츠 프로바이더를 사용해 또 다른 포그라운드 앱이 연결되었을 때


이 외에는 백그라운드 상황으로 간주합니다. 그리고 앱이 백그라운드 상황이더라도 다음과 같은 경우에는 서비스가 정상으로 실행됩니다.


• 우선순위가 높은 파이어베이스 클라우드 메시징(FCM) 처리
• SMS/MMS 메시지와 같은 브로드캐스트 수신
• 알림에서 PendingIntent 실행
• VPN 앱이 포그라운드로 승격되기 전에 VpnService 시작

 

이처럼 서비스가 정상으로 실행되는 포그라운드 상황은 안드로이드 버전이 변경되면서 계속 바뀔 수도 있지만, 어쨌든 중요한 것은 위에 나열한 상황 외에는 서비스가 실행되지 않는다는 점입니다.
그런데 앱이 백그라운드 상황에서도 서비스를 실행할 방법이 하나 있기는 합니다. startFo regroundService() 함수로 인텐트를 시작하면 앱이 백그라운드 상황에서도 서비스가 실행됩니다.

 

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
	startForegroundService(intent)
} else {
	startService(intent)
}

서비스의 백그라운드 제약이 적용된 안드로이드 버전을 고려해서 8(Build.VERSION_CODES.O) 이상일 때는 startForegroundService() 함수로 인텐트를 실행하고, 8 미만일 때는 start Service() 함수로 인텐트를 실행하는 호환성 코드를 작성합니다.
그런데 앱이 백그라운드 상황에서 startForegroundService() 함수로 실행한 서비스는 얼마 후 다음과 같은 오류가 발생하면서 강제로 종료됩니다. 즉, 앱이 백그라운드 상태더라도 startForegroundService() 함수로 서비스를 실행할 수 있지만, 결국 오류가 발생하므로 서비스를 정상으로 유지할 수는 없습니다.

 

Context.startForegroundService() did not then call Service.startForeground()

그렇다면 이런 함수를 왜 제공하는 걸까요? 결론부터 말하면 서비스를 startForegroundService() 함수로 실행했다면 빨리 startForeground() 함수를 호출해 포그라운드 상황으로 만들라는 의미입니다. 그러면 서비스가 종료되지 않습니다.

 

val notification = builder.build()
startForeground(1, notification)

위 코드는 백그라운드 상황에서 startForegroundService() 함수로 실행된 서비스 쪽에 작성합니다. 그런데 startForeground() 함수의 매개변수는 알림 객체이므로 이 함수를 정상으로 실행하려면 다음처럼 매니페스트에 퍼미션을 등록해 줘야 합니다.

 

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

요약하자면 앱이 백그라운드 상황이더라도 startForegroundService() 함수를 이용하면 서비스를 실행할 수 있지만, 빨리 알림을 이용해 앱을 포그라운드 상황으로 만들어야 합니다. 즉, 사용자에게 앱이 실행되고 있다는 것을 알려야 한다는 의미입니다. 그래야만 앱이 백그라운드 제약에서 벗어날 수 있습니다.