선언
- manifest에서 등록할때 foregroundServiceType를 지정해줘야 함. 이는 서비스가 어떤 요구를 필요로 하는지를 설명해줌.
- 타입에는 Camera, connectDevice, mediaPlayback, mediaProjection 등이 있음. 물론, use-permission 단에도 추가해줘야 함.
실행하기
- 실행하려면 startForegroundService를 해줘야하고, 5초 이내에 서비스 내에서 startForeground를 호출해줘야 함.
public abstract ComponentName startForegroundService (Intent service)
public static void startForeground(
@NonNull Service service,
int id,
@NonNull Notification notification,
int foregroundServiceType
)
- service: 해당 서비스 객체를
- id: 절대 0이 되면 안되고, notification의 id를 넘겨줌으로서, NotificationManager가 해당 서비스와 대응되는 Noti를 적절히 다룰 수 있게 해줌.
- notificaiton: foregroundService는 무조건 noti가 필요하기 때문에 이를 생성해서 넘겨줘야 함.
- foregroundServiceType: manifest에 적었던 것과 동일하게 하는 것이 좋다. 권한 확인을 명시적으로 넘기는 것으로 생각할 수 있기 때문에 포함되지 않은 것, 해당 서비스와 관련없는 것들은 제외하고 넣는 것이 좋다. 만약 아예 생략한다면, manifest에 적힌 모든 권한을 검사하게 된다.
stopForeground??
public final void stopForeground (int notificationBehavior)
- 말그대로 "foreground 상태"를 멈추는 것이다. 즉, killed 되는 것이 아닌 백그라운드 상태로 전환되는 것이다.
- notificationBehavior을 총 세 가지가 있다.
- STOP_FOREGROUND_LEGACY: deprecated in api 33 -> 옛날 함수인 staopForeground(boolean)에 false를 담아 호출한다. 버그 & 예상하기 어려운 결과가 많아 사장됨.
- STOP_FOREGROUND_REMOVE: 묶인 notification이 즉시 취소된다.
- STOP_FOREGROUND_DETACH: 묶인 notification가 상태 창에 남아있게 된다.
제한
- API 버전마다 다르니 따로 찾아서 적용해야 함.
- 기본적으로 API 31 이상부터는 앱 자체가 백그라운드에 있을땐 start 할 수 없음.
- service를 시작하기 전, 권한을 확인하고 거부된 경우 -> SecurityException
- TYPE_NONE은 API 34 이상부터는 불가하니 사용하지 말자
background에서 foregroundService의 실행 제한
- 기본적으로 API 31 이상부턴 "몇 가지 예외"를 제외하곤 background에서 foregroundService를 실행할 수 없다.
- 이 예외를 만족시키지 않으면 -> ForegroundServiceStartNotAllowedException
예외는 다음과 같다.
- activity 같은 시각적 트랜지션
- FCM을 이용해서 고-우선순위 메세징을 사용한 경우
- notification, 위젯, 버블을 사용자가 직접 클릭한 경우
- etc...
"앱 사용 중 허가" 권한이 있을 경우 가능
- 하지만, ACCESS_BACKGROUND_LOCATION 등은 앱 심사 시 매우 까다로워 합당한 이유가 있어야 함.
- 그리고 무조건 foreground 상태를 유지해야함.
- checkSelfPermission 자체가 작동하지 않으니 앱 실행 시 권한을 받아놔야 함.
Time Out
- API 35 이상에선, dataSync와 mediaProcessing 타입을 가진 서비스는 해당 앱이 무조건 백그라운드에 있어야 함.
dataSybc: 저장, 업로드, 백업, 패치 등
mediaProcesss: 미디어에 대한 변환
-> 즉, 백그라운드에서 수행될 무거운 작업들
- 해당 앱은 두 타입의 서비스를 24시간 중 6시간만큼 활용 가능하다.
- Service.onTimeout()을 호출하면 foreground 상태에서 내려오고, 이때 stopSelf를 하지 않으면 -> RemoteServiceException: "A foreground service of
type [service type] did not stop within its timeout:
따라서, timeout에 대해 다음 대처가 필요하다.
- onTimeout 호출 이후 stopSelf 호출하기
- 6시간 이상 사용하지 않도록 하기
- dataSync와 mediaProcessing은 무조건 포그라운드로
- 가능한 Workmanager 같은 대체 API를 활용
ForegroundService로 바꾸기
- API 36
- 모든 서비스는 runtime quotas에 종속되어 관리됨.
- 즉, 이전 꼼수들이 먹히지 않음.
- runtime quotas는 앱의 등급(App Standby Buckets)에 따라 결정됨.
- Active: 현재 보고 있거나 방금까지 사용했던 앱
- Working Set: 매우 자주 이용하는 앱 (하루에 한 번씩 꼭)
- Frequent: 자주 사용하지만 매일은 아닌 앱
- Rare: 자주 사용하지 않는 앱
- Restricted: 매우 큰 리소스를 먹거나 권장되지 않는 동작을 하는 앱
- API 35
- 모든 foregroundService는 type을 설정해줘야 함.
- 각 type은 기존의 권한과 유사함. 예를 들어, camera를 사용하려면 FOREGROUND_SERVICE_CAMERA를 사용하면 됨.
- API 31
- 앱이 백그라운드에 있을 때, 몇가지 예외를 제외하곤 Foreground Service를 실행할 수 없다.
- API 30
- Foreground Service가 카메라나 마이크를 사용하면, camera 또는 microphone type을 따로 지정해줘야 함.
- API 29
- API 28
- FOREGROUND_SERVICE 권한을 도입하여 이에 대한 허가를 미리 받아야 한다.