백그라운드 작업 — WorkManager와 Background Fetch
백그라운드 작업 — WorkManager와 Background Fetch
앱이 백그라운드에 있거나 종료된 상태에서도 데이터 동기화, 알림 체크, 캐시 정리 등의 작업을 실행해야 할 때가 있습니다.
백그라운드 작업 방법 비교
| 방법 | 플랫폼 | 특징 |
|---|---|---|
| WorkManager | Android/iOS | 가장 안정적, OS가 스케줄링 |
| Background Fetch | Android/iOS | 주기적 데이터 가져오기 |
| Isolate | 앱 실행 중 | 무거운 연산 분리 |
| FCM | 서버 → 앱 | 서버에서 트리거 |
WorkManager
dependencies:
workmanager: ^0.5.0
초기화
import 'package:workmanager/workmanager.dart';
// 최상위 함수 — 백그라운드에서 실행될 콜백
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
switch (task) {
case 'syncData':
await _syncData();
return true;
case 'cleanCache':
await _cleanCache();
return true;
default:
return false;
}
});
}
Future<void> _syncData() async {
// 데이터 동기화 로직
print('백그라운드 데이터 동기화 실행');
}
Future<void> _cleanCache() async {
// 캐시 정리 로직
print('백그라운드 캐시 정리 실행');
}
// main에서 초기화
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Workmanager().initialize(
callbackDispatcher,
isInDebugMode: true, // 디버그 알림 표시
);
runApp(const MyApp());
}
작업 등록
class BackgroundTaskService {
// 1회성 작업
Future<void> registerOneOffTask() async {
await Workmanager().registerOneOffTask(
'sync-task-1', // 고유 이름
'syncData', // task 이름 (callbackDispatcher에서 매칭)
initialDelay: const Duration(minutes: 5),
constraints: Constraints(
networkType: NetworkType.connected, // 네트워크 연결 시에만
requiresBatteryNotLow: true, // 배터리 충분할 때만
),
inputData: {
'key': 'value',
},
);
}
// 주기적 작업
Future<void> registerPeriodicTask() async {
await Workmanager().registerPeriodicTask(
'periodic-sync',
'syncData',
frequency: const Duration(hours: 1), // 최소 15분 (Android)
constraints: Constraints(
networkType: NetworkType.connected,
),
);
}
// 작업 취소
Future<void> cancelTask(String uniqueName) async {
await Workmanager().cancelByUniqueName(uniqueName);
}
// 모든 작업 취소
Future<void> cancelAllTasks() async {
await Workmanager().cancelAll();
}
}
Background Fetch
주기적으로 데이터를 가져오는 용도에 최적화된 패키지입니다.
dependencies:
background_fetch: ^1.3.0
import 'package:background_fetch/background_fetch.dart';
// 백그라운드 핸들러 (최상위 함수)
@pragma('vm:entry-point')
void backgroundFetchHeadlessTask(HeadlessTask task) async {
final taskId = task.taskId;
if (task.timeout) {
// 타임아웃 처리
BackgroundFetch.finish(taskId);
return;
}
// 작업 수행
await _fetchNewData();
BackgroundFetch.finish(taskId);
}
class BackgroundFetchService {
Future<void> initialize() async {
final status = await BackgroundFetch.configure(
BackgroundFetchConfig(
minimumFetchInterval: 15, // 분 단위
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true,
requiresStorageNotLow: false,
requiresBatteryNotLow: false,
requiresCharging: false,
requiresDeviceIdle: false,
requiredNetworkType: NetworkType.ANY,
),
_onBackgroundFetch, // 포그라운드/백그라운드
_onBackgroundTimeout, // 타임아웃
);
print('BackgroundFetch 상태: $status');
// 헤들리스 태스크 등록 (앱 종료 시에도 실행)
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
}
void _onBackgroundFetch(String taskId) async {
print('백그라운드 fetch 실행: $taskId');
await _fetchNewData();
BackgroundFetch.finish(taskId);
}
void _onBackgroundTimeout(String taskId) {
print('백그라운드 타임아웃: $taskId');
BackgroundFetch.finish(taskId);
}
Future<void> _fetchNewData() async {
// 새 데이터 가져오기
}
}
플랫폼별 제약사항
iOS
- 백그라운드 실행 시간이 약 30초 로 제한됩니다
- OS가 실행 빈도를 조절합니다 (사용 패턴에 따라)
Info.plist에 백그라운드 모드 추가 필요:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
</array>
Android
- WorkManager의 최소 주기는 15분 입니다
- 배터리 절약 모드에서 제한될 수 있습니다
- Android 12+에서 정확한 알람은 별도 권한 필요
면접 포인트: iOS와 Android 모두 배터리 최적화를 위해 백그라운드 작업을 제한합니다. 정확한 실행 시간을 보장할 수 없으며, OS의 스케줄링에 의존합니다.
백그라운드 작업 주의사항
// 1. 콜백은 최상위 함수여야 함
@pragma('vm:entry-point')
void myCallback() { ... } // 클래스 메서드 불가
// 2. 플러그인 초기화가 필요할 수 있음
void callbackDispatcher() {
Workmanager().executeTask((task, data) async {
// Firebase 등 플러그인 초기화
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// 작업 수행
return true;
});
}
// 3. 오래 걸리는 작업은 피하기 (iOS 30초 제한)
// 4. 작업 완료 알림
// finish() 호출을 잊으면 OS가 앱을 비정상으로 판단
BackgroundFetch.finish(taskId);
정리
- WorkManager: 가장 안정적인 백그라운드 작업 관리 (1회성/주기적)
- Background Fetch: 주기적 데이터 가져오기에 특화
- 콜백 함수는 반드시 ** 최상위 함수 **로 선언해야 합니다
- iOS는 30초, Android WorkManager 최소 주기는 15분 제한이 있습니다
- 백그라운드 작업 완료 시
finish()를 반드시 호출하세요 - 정확한 실행 시간은 보장되지 않으며 OS 스케줄링에 의존합니다
댓글 로딩 중...