[FLUTTER] Background 처리
프로그램 개발 시 백그라운드 처리가 필요한 경우가 무척이나 많다.
실시간 위치정보나 Notification, FCM 같은 경우가 특히 그러하다.
그런데 Debugging Mode에서는 문제가 없었는데 스토어와 마켓에 올리기 위해 Release Mode로 빌드했더니, Release Mode에서는 백그라운드 처리가 정상적으로 되지 않았던 것이다. 개발환경의 Version 문제 등 놓친 부분이 있기도 하겠으나 양 진영의 플랫폼은 배터리 관리에 무척이나 신경쓰고 있었던 것 같다.
개발 중에는 Debugging Mode로 내 컴퓨터와 폰을 USB로 연결해서 테스트(Logger 확인을 해야 하므로…)하기 때문에, 화면이 꺼질일이 없었고 테스트 목적으로 화면을 끄더라도 USB연결로 인해 배터리가 충전 중 이었으니, 백그라운드 처리에 문제가 없었는데 USB연결을 끊고 Release앱을 실행시켜서 테스트 해보니 Notification 처리가 제대로 되지 않았다.
특히, 개발 중이던 앱 특성상 ServerPushMessage가 아닌 Local Message를 사용해야 했는데 충전 상태가 아닌 OS는 배터리를 위해 일정 시간 이후 백그라운드 상태의 앱들을 모두 Sleep상태로 전환시키는 듯 했다. (지금은 필요에 의해 FCM 적용까지 완료)
지금 생각해 보니 FCM은 BackgroundService 권한하고는 상관 없는 것 같다. 앱 종료(Terminated) 상태여도 아래 표 내용과 같이 몇가지 조건만 충족되면 알림은 가능하고 OS가 직접 Notification 메세지를 보낼 수 있게 작업하면 되기 때문이다.
메시지 유형 | 앱 종료 상태에서 수신 가능 여부 | 수신 처리 방식 |
Notification 메시지 (notification 필드 포함) | 가능 | OS가 직접 알림 표시 |
Data 메시지 (data 필드만 있음) | 불가 | 앱이 실행 중일 때만 수신 가능 |
Mixed 메시지 (notification + data) | 알림은 표시, data는 수신 안됨 | 알림 탭 시 앱이 열리면 data 전달 |
테스트 결과 Release Mode의 화면꺼짐(Background) 상태에서도 특정 알림 조건을 Check를 하는 Process가 정상적으로 실행되었으며, 알림을 전송해야 할 상태가 되면 Sleep상태의 App을 깨우고 Local Notification을 전송한다.
만들고 있는 앱은 세가지 중요한 기능을 충족 해야 했다.
첫번째. 휴대폰 화면이 꺼져 있어도 GPS정보를 수신해야 한다.
두번째. 앱이 종료(백그라운드 상태와는 다름)되었어도 알림 메세지를 받을 수 있어야 한다.
세번째. GooglePlay 등록 시 BackgroundService 권한 심사를 받는 것이 불편해서, BackgroundService권한 없이 사용.
AndroidManifest.xml 에 <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> 이 권한을 주면 해결되지만, ACCESS_BACKGROUND_LOCATION 권한을 주게 되면 사용자에게 권한요청도 추가로 해야 하고, 결정적으로 추후 안드로이드 마켓에 앱 등록 하려면 ACCESS_BACKGROUND_LOCATION 권한을 사용해야 하는 이유에 대해 구구절절 설명을 해야하고 심사를 거쳐서 통과 되어야 등록할 수 있다. (근데 이게 은근 귀찮고 짜증난다. ㅠㅠ)
Android 10 (API 29) 이상에서는 위치 권한이 민감한 권한으로 분류되어, 사용 목적이 명확해야 하고 남용을 방지하려는 Google의 정책 때문이다.
이 때문에 Background Service를 Foreground Service로 대체 했더니 원하던 상황에서도 GPS 수신이 정상 작동한다.
(제한 조건이겠지만 ForegroundService로 대체 한다는 의미는 바로 사용자가 앱을 사용하는 동안만 위치를 추적한다는 의미와 동일하다.)
Foreground Service로 대체하기 전에 다음의 내용을 숙지하자.
- 사용 패키지 : flutter_background, geoLocator or location
(필자의 경우 flutter_background_2 를 사용했는데, 이녀석은 가끔 앱 실행 초 중국어가 콘솔에 출력 될 때가 있다) - FOREGROUND_SERVICE 권한 필요
- flutter_background로 위치 추적 중임을 OS에 알림
- ACCESS_FINE_LOCATION만 있으면 OK
시작해 보자.~~~
앱이 실행중일 때에만 위치 추적 (화면꺼짐 포함)
※ 앱이 메모리에 실행되어 있기만 하면 된다.
만약 앱이 실행중이 아니어도 (앱종료상태 : Terminated) 위치 수신이 필요하다면 ACCESS_BACKGROUND_LOCATION 권한 요청은 필수이며, 이때는 background_locator_2 를 사용하는 것이 좀더 정신건강에 좋지 않을까 싶다. (주기적인 위치 추적이 필요할 경우 workmanager 참고).
GPS 와 FCM 적용 2가지에 대해 아래 표로 정리해 보았다.
기능 | 앱 실행 중 | 앱 꺼짐 상태 | Google 심사 |
GPS 추적 (ForegroundService) | 가능 | 불가 | 불필요 |
GPS 추적 (Background Location) | 가능 | 가능 | 필요 |
FCM (notification 포함) | 가능 | 가능 | 불필요 |
FCM (data-only) | 가능 | 불가 | 불필요 |
Flutter로 백그라운드 기능을 구현할 때는 단순히 코드만 짜는 것보다, OS 정책과 마켓 심사까지 고려한 설계가 필수다. 앱이 위치 추적을 해야 하는 진짜 이유가 없다면 background_location 권한 없이도 충분히 유연하게 만들 수 있다.
👉 백그라운드 GPS 추적 + 푸시 알림이 필요한 앱이라면, 위 표를 기준으로 "정확히 언제까지 살아 있어야 하나?" 를 먼저 정의하고 접근하자
구현 코드는 아래와 같다. (필자의 코드를 직접 넣으려고 했으나 주석부터 블로그 주제와는 관련없는 관련 코드가 너무 많고 지저분해서, 참고했던 코드의 이미지로 갈음하고자 한다.)
💡 1. AndroidManifest 설정
💡 2. Foreground Service 시작
💡 3. 위치 스트림 구독 (예: Geolocator)
혹, 필자와 같은 GPS 수신 & FCM 백그라운드 처리에 고민 중이신 개발자들이 있다면,
Foreground Service 권한으로 Background Service 기능을 대체하시기 바란다.