Flutter Foreground 서비스로 실시간 데이터 업데이트하는 5가지 방법






Flutter Foreground 서비스로 실시간 데이터 업데이트하는 5가지 방법

Flutter 앱을 개발하다 보면 백그라운드에서도 지속적으로 데이터를 수집하고 업데이트해야 하는 상황이 많이 발생합니다. 스마트워치 앱에서 심박수를 계속 모니터링해야 한다거나, 위치 기반 서비스를 제공할 때도 그렇습니다. 이러한 요구사항을 안정적으로 구현하기 위해서는 Foreground 서비스를 올바르게 이해하고 활용해야 합니다.

이 글에서는 Flutter에서 Foreground 서비스를 활용하여 실시간 데이터를 업데이트하는 방법을 단계별로 설명하겠습니다.


목차


1. Foreground 서비스란 무엇인가

Foreground 서비스는 사용자가 서비스의 동작을 인지할 수 있는 상태의 서비스를 의미합니다. 가장 큰 특징은 항상 화면 상단에 지속적인 알림(Notification)을 표시해야 한다는 점입니다.

예를 들어, 음악 스트리밍 앱에서 재생 중인 음악 정보가 상단에 보이거나, 운동 기록 앱에서 진행 중인 운동 시간이 표시되는 경우가 바로 Foreground 서비스입니다.

Foreground 서비스의 특징

  • 사용자에게 항상 보이는 알림을 제공
  • 시스템이 임의로 종료하지 않음
  • 백그라운드 서비스보다 높은 우선순위 유지
  • 지속적인 작업 수행 가능

2. Background와 Foreground를 구분하는 이유

왜 굳이 Background와 Foreground를 나눌까요? 그 이유는 사용자 경험과 시스템 리소스 관리에 있습니다.

Doze 모드의 위협

Android 6.0(API 레벨 23, 마시멜로)부터 도입된 Doze 모드는 배터리 절약을 위해 백그라운드에서 실행 중인 서비스를 무작위로 종료합니다. 서비스가 백그라운드에서만 실행되면, 아무 경고 없이 중단될 수 있다는 의미입니다.

하지만 Foreground 서비스는 사용자에게 명시적으로 표시되기 때문에, 시스템이 이를 중단하지 않습니다. 이것이 바로 안정적인 데이터 수집이 필요한 작업에서 Foreground 서비스를 사용해야 하는 이유입니다.

우선순위 관리

여러 백그라운드 작업 중에서도 Foreground 서비스는 최우선 순위로 처리됩니다. 제한된 시스템 리소스가 있을 때, 가장 중요한 작업부터 진행하도록 하는 안드로이드의 전략이라고 할 수 있습니다.


3. Flutter에서 Foreground 서비스 구현하기

Flutter에서 Foreground 서비스를 구현하는 가장 일반적인 방법은 flutter_background_service 패키지를 사용하는 것입니다.

기본 구현 단계

첫 번째 단계: 서비스 초기화

앱이 실행될 때 백그라운드 서비스를 초기화해야 합니다. main() 함수에서 WidgetsFlutterBinding을 보장한 후, 서비스 초기화 함수를 호출합니다.

이 과정에서 Android와 iOS 각각에 대한 설정을 따로 진행해야 합니다. Android의 경우 foregroundMode를 활성화하고, iOS의 경우 백그라운드 리프레시 모드를 설정합니다.

두 번째 단계: 알림 설정

Foreground 서비스는 반드시 알림을 제공해야 합니다. 이 알림은 단순한 UI 요소가 아니라 서비스 유지의 필수 요건입니다. 알림에는 현재 서비스가 어떤 작업을 하고 있는지를 나타내는 정보를 포함시켜야 합니다.

예를 들어 “위치 기록 중…” 또는 “심박수 모니터링 중…” 같은 텍스트가 적절합니다.

세 번째 단계: onStart 콜백 구현

flutter_background_service에서는 서비스가 시작될 때 호출되는 onStart 콜백을 구현합니다. 이곳에서 실제 데이터 수집 로직이 시작됩니다.

onStart 콜백에서는 DartPluginRegistrant.ensureInitialized()를 호출하여 Dart 플러그인들이 정상적으로 초기화되도록 해야 합니다.

iOS 특화 설정

iOS에서는 Info.plist 파일에 BGTaskSchedulerPermittedIdentifiers를 등록해야 합니다. 이는 “dev.flutter.background.refresh”라는 식별자를 추가하고, AppDelegate.swift에서 이를 인식하도록 설정하는 과정입니다.

이렇게 설정하면 iOS에서는 제한적이지만 주기적으로 백그라운드 작업을 수행할 수 있게 됩니다.


4. 실시간 데이터 업데이트 방법

Foreground 서비스가 구성된 후, 실제로 데이터를 수집하고 업데이트하는 방법은 여러 가지가 있습니다.

방법 1: 알람 매니저를 통한 주기적 업데이트

Android의 AlarmManager를 사용하면 정해진 시간 간격마다 작업을 수행할 수 있습니다. 이 방법은 특히 배터리 효율이 중요한 경우에 유용합니다.

AlarmManager는 BleService 같은 백그라운드 서비스를 주기적으로 호출할 수 있도록 설정합니다. PendingIntent를 사용하여 특정 Intent를 정해진 시간에 발생시키는 방식입니다.

방법 2: 데이터베이스 트랜잭션을 활용한 안전한 업데이트

실시간으로 들어오는 데이터를 처리할 때는 데이터 중복이나 손실을 방지해야 합니다. 이를 위해 데이터베이스 트랜잭션을 사용합니다.

예를 들어, 걸음 수를 기록할 때는 기존 데이터를 먼저 확인한 후, 더 큰 값이 들어오면 업데이트하고, 그렇지 않으면 새로운 기록으로 추가하는 방식입니다. 이러한 로직을 트랜잭션으로 묶으면 동시성 문제를 피할 수 있습니다.

방법 3: UI 채널과 백그라운드 채널 분리

앱이 활성 상태일 때와 백그라운드 상태일 때 데이터를 처리하는 방식을 다르게 해야 합니다.

앱이 포그라운드에 있을 때는 UI 채널을 통해 데이터를 전송하여 화면에 실시간으로 표시하고, 백그라운드 상태에서는 백그라운드 채널을 통해 데이터를 처리합니다. 이렇게 분리하면 UI 스레드를 차단하지 않으면서도 일관된 데이터 흐름을 유지할 수 있습니다.

방법 4: Stream을 활용한 실시간 업데이트

Drift(Flutter의 ORM 패키지)를 사용하면 데이터베이스의 데이터를 Stream으로 감시할 수 있습니다.

위치 정보나 센서 데이터 같이 계속 변하는 정보를 다룰 때, Stream을 통해 변경사항을 실시간으로 감지하고 UI를 업데이트할 수 있습니다. 이 방식은 특히 Riverpod 같은 상태 관리 라이브러리와 결합하면 매우 효과적입니다.

방법 5: Broadcast Receiver를 통한 데이터 전달

백그라운드 서비스에서 수집한 데이터를 현재 활성화된 Activity에 전달해야 할 때가 있습니다. 이 경우 Broadcast Receiver를 사용합니다.

로컬 Broadcast(LocalBroadcastManager)를 사용하면 현재 프로세스 내에서만 신호를 전달하므로, 보안상 더 안전하면서도 효율적입니다. 백그라운드 서비스가 데이터를 수집할 때마다 Broadcast를 발송하면, Activity에서 이를 수신하여 UI를 업데이트할 수 있습니다.


5. 배터리 최적화와 실무 주의사항

Foreground 서비스를 안정적으로 운영하려면 여러 실무적 고려사항이 있습니다.

배터리 최적화 예외 설정

일부 안드로이드 기기들, 특히 중국산 스마트폰의 경우 배터리 최적화로 인해 백그라운드 프로세스를 자동으로 종료합니다. 이를 방지하려면 사용자가 앱을 배터리 최적화 제외 목록에 추가해야 합니다.

앱에서는 사용자에게 배터리 최적화 설정 화면으로 유도하는 기능을 제공하는 것이 좋습니다.

타이머의 정확성 유지

스톱워치나 타이머 같이 시간 흐름을 정확히 유지해야 하는 기능을 백그라운드에서 구현할 때는 특별한 주의가 필요합니다.

단순히 변수로 카운트를 증가시키는 방식보다는 시작 시간과 현재 시간의 차이를 계산하는 방식이 더 정확합니다

댓글 남기기