Expo Location 구현 핵심 요약
현재 위치 1회 조회, 화면이 열린 동안의 구독, 백그라운드 추적은 권한과 실행 제약이 서로 다릅니다. 필요한 범위를 먼저 정하고, foreground 권한부터 요청한 뒤 background는 제품 핵심 기능일 때만 별도 설명과 동의 흐름을 만드세요. 백그라운드 위치는 운영체제·사용자 설정·앱 종료 상태에 따라 중단될 수 있으므로 “항상 추적”을 보장하지 않습니다.
버전 기준: 2026-07-19 Expo SDK 57 최신 문서에서 expo-location ~57.0.5, expo-task-manager ~57.0.5를 확인했습니다. 설치는 버전을 직접 고정하기보다 npx expo install로 현재 프로젝트 SDK와 맞추고 lockfile을 기준으로 검증하세요.
1. 기능 요구를 API로 바로 매핑합니다

| 요구 | API | 핵심 제약 |
|---|---|---|
| 최근 좌표를 빠르게 표시 | getLastKnownPositionAsync |
오래됐거나 부정확할 수 있어 maxAge·accuracy 검사 필요 |
| 현재 좌표 1회 조회 | getCurrentPositionAsync |
센서·환경에 따라 늦거나 실패할 수 있음 |
| 화면이 열린 동안 이동 반영 | watchPositionAsync |
foreground에서만 update, 구독 해제 필수 |
| 앱이 뒤에 있을 때 경로 기록 | startLocationUpdatesAsync |
TaskManager·background 권한·native config·개발 빌드 필요 |
| 영역 진입·이탈 감지 | startGeofencingAsync |
플랫폼별 region 수와 종료 상태 동작 차이 |
정확한 최신 API와 플랫폼 표는 Expo Location 공식 문서을 기준으로 확인합니다. 지도에 점 하나를 찍는 기능에 background 권한을 요청하지 말고, 사용자가 기대하는 핵심 기능에 필요한 최소 권한만 사용하세요.
2. 설치와 app config는 빌드 전에 결정합니다
npx expo install expo-location expo-task-manager
{
"expo": {
"plugins": [
[
"expo-location",
{
"locationWhenInUsePermission": "현재 위치를 표시하기 위해 위치를 사용합니다.",
"locationAlwaysAndWhenInUsePermission": "이동 기록 기능을 켠 동안 위치를 사용합니다.",
"isIosBackgroundLocationEnabled": true,
"isAndroidBackgroundLocationEnabled": true
}
]
]
}
}
config plugin 변경은 native 설정을 바꾸므로 새 binary를 만들어야 합니다. foreground 전용 앱이라면 background 옵션을 켜지 않습니다. iOS 설명 문구는 기능 목적을 구체적으로 쓰고, Android background·foreground service 권한은 앱 심사와 개인정보 고지까지 함께 검토합니다.
3. 현재 위치와 foreground 구독
캐시 좌표를 쓸 수 있는 조건을 먼저 정합니다
import * as Location from 'expo-location';
export async function readCurrentLocation() {
const permission = await Location.requestForegroundPermissionsAsync();
if (permission.status !== 'granted') return { kind: 'denied' } as const;
const cached = await Location.getLastKnownPositionAsync({
maxAge: 30_000,
requiredAccuracy: 500,
});
const location = cached ?? await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Balanced,
});
return { kind: 'success', location } as const;
}
날씨·매장 검색은 수백 미터 오차와 수십 초 캐시가 허용될 수 있지만, 안전 기능이나 정밀 경로 기록은 같은 기준을 쓸 수 없습니다. accuracy와 timestamp를 UI에 전달하고, 권한 거부·위치 서비스 꺼짐·시간 초과 상태를 각각 안내합니다.
watch 구독은 화면 생명주기에 맞춰 해제합니다
const subscription = await Location.watchPositionAsync(
{ accuracy: Location.Accuracy.Balanced, distanceInterval: 20 },
(nextLocation) => updateMap(nextLocation),
(reason) => reportLocationError(reason),
);
// 화면을 떠날 때 반드시 호출
subscription.remove();
정확도를 무조건 최고로 두면 배터리와 발열 비용이 커집니다. 제품 요구에 맞춰 accuracy, time interval, distance interval을 결정하고 실기기에서 전력 사용과 update 간격을 측정합니다.
4. background task는 top-level에서 정의합니다

import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
const TASK_NAME = 'route-location';
// 컴포넌트 내부가 아니라 앱이 로드할 수 있는 모듈의 top-level에 정의
type LocationTaskData = { locations: Location.LocationObject[] };
TaskManager.defineTask<LocationTaskData>(
TASK_NAME,
async ({ data, error }) => {
if (error) {
await reportBackgroundError(error.message);
throw new Error(error.message);
}
if (!data?.locations.length) return;
// headless 실행이 끝나기 전에 영속 queue 기록을 완료하고 실패를 전달합니다.
await enqueueEncryptedLocations(data.locations);
},
);
export async function startTracking() {
const foreground = await Location.requestForegroundPermissionsAsync();
if (foreground.status !== 'granted') return false;
const background = await Location.requestBackgroundPermissionsAsync();
if (background.status !== 'granted') return false;
await Location.startLocationUpdatesAsync(TASK_NAME, {
accuracy: Location.Accuracy.Balanced,
distanceInterval: 50,
foregroundService: {
notificationTitle: '이동 기록 중',
notificationBody: '위치 추적을 중지하려면 앱 설정을 여세요.',
},
});
return true;
}
Expo 공식 문서는 background task를 top-level scope에서 정의하도록 요구하고 executor 반환형을 Promise로 규정합니다. 위 예제처럼 callback을 async로 만들고 영속 queue 저장을 await해야 TaskManager가 완료·실패를 관찰할 수 있습니다. React 화면 상태에 의존하거나 Promise를 반환하지 않는 fire-and-forget 작업은 headless 실행 중 bundle이 종료될 때 유실될 수 있습니다. iOS background location은 Expo Go에서 지원되지 않으므로 development build와 실제 기기로 검증합니다. Android도 Expo Go의 foreground/background service 제약이 있으므로 Expo TaskManager 공식 문서와 Expo Location 공식 문서의 현재 지원표를 함께 봅니다.
앱이 강제 종료됐을 때 동작은 플랫폼과 제조사에 따라 다릅니다. Expo 문서상 Android는 종료된 앱이 위치·geofence 이벤트로 자동 재시작되지 않으며, iOS geofence는 시스템이 앱을 다시 시작할 수 있는 차이가 있습니다. 이를 “24시간 누락 없는 추적”으로 광고하지 말고 누락·재개·중복 전송을 견디는 queue와 idempotency를 설계합니다.
5. Android와 iOS 권한 흐름을 분리합니다
Android
iOS
6. 개인정보·배터리·실기기 테스트
7. 명시적 결론과 다음 행동
결론: 위치 기능은 API 호출보다 권한·실행 상태·개인정보·배터리 설계가 먼저입니다. 현재 위치만 필요하면 foreground API에서 끝내고, background는 제품 핵심 가치와 플랫폼 정책을 설명할 수 있을 때만 추가하세요. 다음 행동은 요구사항을 1회 조회·foreground 구독·background 추적 중 하나로 고르고, 권한 거부를 포함한 실기기 테스트 표를 먼저 만드는 것입니다.
“Expo Location 사용법: 현재 위치와 백그라운드 추적 처리”에 대한 1개의 생각