백그라운드 작업 — 포그라운드 서비스와 Background Fetch
모바일 OS는 배터리 절약을 위해 백그라운드 앱을 적극적으로 제한합니다. 올바른 방법을 사용하지 않으면 작업이 중단됩니다.
백그라운드 제약사항
iOS:
- Background App Refresh (OS가 적절한 시점에 실행)
- 위치 추적 (continuous background location)
- 오디오 재생, VOIP
- 명시적으로 Background Modes를 설정해야 함
Android:
- Foreground Service (알림 표시 필수)
- WorkManager (지연 가능한 백그라운드 작업)
- AlarmManager (정확한 시간 실행)
- Doze Mode / App Standby 제한
expo-background-fetch
npx expo install expo-background-fetch expo-task-manager
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';
const BACKGROUND_FETCH_TASK = 'background-fetch-task';
// 백그라운드 태스크 정의 (최상위 레벨)
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
const now = Date.now();
console.log(`백그라운드 태스크 실행: ${new Date(now).toISOString()}`);
try {
// 새 데이터 확인, 동기화 등
const hasNewData = await checkForNewData();
if (hasNewData) {
await syncData();
// 로컬 알림으로 사용자에게 알림
await showLocalNotification('새 데이터가 있습니다');
}
return hasNewData
? BackgroundFetch.BackgroundFetchResult.NewData
: BackgroundFetch.BackgroundFetchResult.NoData;
} catch (error) {
return BackgroundFetch.BackgroundFetchResult.Failed;
}
});
// 태스크 등록
async function registerBackgroundFetch() {
await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 15 * 60, // 최소 15분 간격
stopOnTerminate: false, // 앱 종료 후에도 실행
startOnBoot: true, // 재부팅 후 실행
});
}
백그라운드 위치 추적
import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
const LOCATION_TASK = 'background-location-task';
TaskManager.defineTask(LOCATION_TASK, ({ data, error }) => {
if (error) {
console.error('위치 추적 에러:', error);
return;
}
const { locations } = data as { locations: Location.LocationObject[] };
const latest = locations[0];
console.log('백그라운드 위치:', latest.coords);
// 서버에 위치 전송
sendLocationToServer(latest.coords);
});
async function startBackgroundLocation() {
const { status: foreground } = await Location.requestForegroundPermissionsAsync();
const { status: background } = await Location.requestBackgroundPermissionsAsync();
if (foreground !== 'granted' || background !== 'granted') {
Alert.alert('위치 권한이 필요합니다');
return;
}
await Location.startLocationUpdatesAsync(LOCATION_TASK, {
accuracy: Location.Accuracy.Balanced,
distanceInterval: 50, // 50m마다 업데이트
showsBackgroundLocationIndicator: true, // iOS 상태바 표시
foregroundService: {
notificationTitle: '위치 추적 중',
notificationBody: '앱이 위치를 추적하고 있습니다',
},
});
}
async function stopBackgroundLocation() {
await Location.stopLocationUpdatesAsync(LOCATION_TASK);
}
주의사항
- 배터리 소모: 백그라운드 작업은 배터리를 빠르게 소모합니다
- OS 제한: iOS는 Background Fetch 실행 시점을 OS가 결정합니다
- 사용자 신뢰: 백그라운드 위치 추적은 사용자에게 명확히 고지해야 합니다
- 스토어 심사: 불필요한 백그라운드 권한은 심사 거절 사유가 됩니다
정리
- 백그라운드 작업은 OS의 엄격한 제한 을 받으므로 공식 API를 사용하세요
- Background Fetch 는 OS가 적절한 시점에 실행합니다 — 정확한 타이밍 보장 불가
- 위치 추적은 배터리 소모가 크므로
distanceInterval을 적절히 설정하세요 - 사용자에게 백그라운드 활동을 명확히 고지 하세요 — 앱 심사와 사용자 신뢰 모두에 필요합니다