Flutter iOS / Android 백그라운드 작업(WorkManager, BGTaskScheduler) 안 끊기고 안정 실행하기

모바일 앱 서비스(위치 추적, 오프라인 데이터 동기화, 주기적 백그라운드 데이터 패치, 로컬 알림 예약 등)를 개발할 때 가장 까다로운 요구사항 중 하나는 **“앱이 꺼져있거나 백그라운드에 있을 때도 백그라운드 작업이 죽지 않고 실행되는 것”**이다.
Flutter 앱 개발 시 단순히 Timer.periodic이나 일반 비동기 함수를 사용하면 앱이 백그라운드로 진입하는 순간 OS(Android/iOS)의 배터리 최적화 정책에 의해 즉시 서스펜드(Suspend)되거나 메모리에서 킬(Kill)당한다.
특히 Android의 제조사별(삼성, 샤오미) 강도 높은 Doze Mode 정책과 iOS의 엄격한 BGTaskScheduler 제약은 백그라운드 작업의 주기적 실행을 방해하는 큰 장애물이다.
이 글에서는 WorkManager 패키지를 활용해 Android와 iOS에서 모두 안정적으로 작동하는 백그라운드 작업 아키텍처, @pragma('vm:entry-point') 콜백 분리 기법, iOS Info.plist 설정, 그리고 시뮬레이터/ADB 디버깅 기법을 안내한다.
핵심 요약
- OS별 백그라운드 구동 메커니즘: Android는 WorkManager (PeriodicWorkRequest, 제약조건 처리)를 사용하며, iOS는 BGTaskScheduler (
BGAppRefreshTask,BGProcessingTask)를 기반으로 작동한다.- Isolate 분리 필수: 백그라운드 작업은 UI 메인 Isolate와 별개의 백그라운드 Isolate에서 독립 실행되므로, 최상위 콜백 함수에
@pragma('vm:entry-point')어노테이션을 붙여 트리밍을 방지해야 한다.- iOS 실행 제약: iOS 백그라운드 작업은 정확한 정시 실행을 보장하지 않으며, OS 판단에 따라 30초 내외의 실행 시간이 부여된다.
- 제조사 배터리 최적화 회피: Android에서는 제약 조건(
Constraints(networkType: NetworkType.connected)) 설정과 함께 필요 시 Foreground Service를 병행해야 지속성을 확보할 수 있다.
1. Android WorkManager vs iOS BGTaskScheduler 비교
두 운영체제는 백그라운드 작업을 다루는 철학이 상이하다.
| 비교 항목 | Android WorkManager | iOS BGTaskScheduler |
|---|---|---|
| 최소 주기 단위 | 최소 15분 (PeriodicWork) | OS가 배터리 및 사용 패턴에 따라 결정 |
| 실행 시간 제한 | 조건 충족 시 최대 10분 (Foreground Service 전환 시 무제한) | 작업당 최대 30초 수준의 엄격한 시간 제한 |
| 제약 조건(Constraints) | 와이파이 연결, 충전 중, 배터리 여유 등 세분화 설정 가능 | Background Modes 권한 등록 필요 |
| 실행 보장성 | 높은 편 (Doze Mode 탈출 작업 가능) | 낮음 (배터리 부족 시 OS가 작업 취소) |
2. Flutter workmanager 패키지 구성 및 코드 작성
1) 백그라운드 엔트리 포인트 정의 (callbackDispatcher)
백그라운드 작업은 UI 렌더링 컨텍스트가 없으므로 최상위(Top-level) 함수로 선언하고 @pragma('vm:entry-point')를 반드시 명시해야 한다.
import 'package:flutter/material.dart';
import 'package:workmanager/workmanager.dart';
// 백그라운드 Isolate의 엔트리 포인트
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((taskName, inputData) async {
switch (taskName) {
case 'syncDataTask':
debugPrint("백그라운드 데이터 동기화 시작: $inputData");
// HTTP 요청 또는 로컬 DB 작업 수행
final success = await _performDataSync();
return Future.value(success);
case 'simplePeriodicTask':
debugPrint("주기적 백그라운드 작업 실행");
return Future.value(true);
default:
return Future.value(true);
}
});
}
Future<bool> _performDataSync() async {
// 실제 백그라운드 API 호출 또는 SQLite 저장 로직
await Future.delayed(const Duration(seconds: 2));
return true;
}
2) 앱 시작 시 WorkManager 초기화 및 작업 등록
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 1. WorkManager 초기화 (콜백 디스패처 등록)
await Workmanager().initialize(
callbackDispatcher,
isInDebugMode: true, // 개발 중 로그 출력
);
runApp(const MyApp());
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
void _scheduleBackgroundTask() {
// Android: 15분마다 주기적 작업 등록
Workmanager().registerPeriodicTask(
"periodic-sync-id",
"syncDataTask",
frequency: const Duration(minutes: 15),
constraints: Constraints(
networkType: NetworkType.connected, // 인터넷 연결 시에만 구동
requiresBatteryNotLow: true, // 배터리가 충분할 때만
),
inputData: <String, dynamic>{'userId': 'user_1234'},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('WorkManager 백그라운드 데모')),
body: Center(
child: ElevatedButton(
onPressed: _scheduleBackgroundTask,
child: const Text('백그라운드 작업 예약'),
),
),
);
}
}
3. iOS 필수 설정 (Info.plist)
iOS에서 WorkManager 및 BGTaskScheduler를 정상 작동시키려면 ios/Runner/Info.plist에 BGTaskPermittedIdentifiers 및 Background Modes를 등록해야 한다.
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
</array>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>workmanager.background.task</string>
<string>syncDataTask</string>
</array>
4. 백그라운드 작업 CLI 디버깅 및 시뮬레이션 기법
백그라운드 작업은 15분 이상 기다리지 않고 터미널 CLI 명령어로 즉시 강제 실행시켜 테스트해야 한다.
1) Android ADB 강제 실행 명령어
# WorkManager 작업 강제 트리거
adb shell cmd jobscheduler run -f dev.effidev.flutterapp 1001
2) iOS Xcode LLDB 시뮬레이션 명령어
iOS 시뮬레이터 실행 중 Xcode 디버거(LLDB)에서 아래 명령어를 입력하면 BGTaskScheduler 작업을 즉시 실행할 수 있다.
(lldb) e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"syncDataTask"]
결론
WorkManager와 백그라운드 Isolate 분리를 올바르게 적용하면, Android의 Doze Mode와 iOS의 BGTaskScheduler 제약 속에서도 킬당하지 않고 안정적인 백그라운드 작업을 유지할 수 있다.
네트워크 제약 조건 설정과 @pragma('vm:entry-point') 지침을 준수하여 신뢰성 높은 백그라운드 동기화 시스템을 구축해보자.