정확도와 전경/배경으로 나뉜 단계적 권한.
- ACCESS_COARSE_LOCATION — 대략적 위치 (약 1~3km)
- ACCESS_FINE_LOCATION — 정확한 위치 (GPS)
- ACCESS_BACKGROUND_LOCATION — 앱이 안 보일 때도 위치 (Android 10+)
한 번에 다 요청할 수 없다
Android 11+ 는 전경 위치와 백그라운드 위치를 함께 요청하면 거부한다
순서
- ① 전경 위치를 먼저 받는다
- ② 백그라운드가 정말 필요할 때, 왜 필요한지 설명하고
- ③ 별도로 요청한다 → 시스템 설정 화면으로 이동해 '항상 허용' 을 골라야 한다
대부분의 앱은 백그라운드 위치가 필요 없다 — Play 스토어 심사에서도 강한 정당화를 요구한다
Android 12+ 대략/정확 선택
launcher.launch(arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION))
// 결과에서 무엇을 받았는지 확인해야 한다
val fine = result[ACCESS_FINE_LOCATION] == true
val coarse = result[ACCESS_COARSE_LOCATION] == true
사용자가 "대략적인 위치" 만 고를 수 있다
- FINE 을 요청해도 COARSE 만 허용될 수 있다
- 정확도가 낮아도 동작하는 대체 경로를 만들어야 한다
위치 읽기
val client = LocationServices.getFusedLocationProviderClient(ctx)
// 마지막 알려진 위치 — 가장 싸다. 하지만 null 이거나 오래됐을 수 있다
client.lastLocation.addOnSuccessListener { it?.let(::use) }
// 지속 갱신
val request = LocationRequest.Builder(Priority.PRIORITY_BALANCED_POWER_ACCURACY, 10_000)
.setMinUpdateDistanceMeters(50f)
.build()
client.requestLocationUpdates(request, callback, Looper.getMainLooper())
배터리와 정확도는 늘 트레이드오프
-
PRIORITY_HIGH_ACCURACY — GPS. 정확하지만 배터리를 크게 쓴다
-
PRIORITY_BALANCED_POWER_ACCURACY 와이파이·기지국. 약 100m. 대부분 충분하다
-
PRIORITY_LOW_POWER — 약 10km
-
PRIORITY_PASSIVE — 다른 앱이 요청할 때 묻어간다
-
갱신 주기를 늘린다 (1초 → 10초)
-
최소 이동 거리를 준다 (50m 이상 움직였을 때만)
-
화면이 안 보이면 반드시 멈춘다 (onStop 에서 removeLocationUpdates)
센서도 같은 규칙
override fun onResume() {
super.onResume()
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI)
}
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(listener) // ★ 안 하면 화면이 꺼져도 계속 돈다
}
센서는 시스템이 자동으로 멈춰 주지 않는다 등록/해제 짝맞춤이 배터리를 지키는 유일한 장치다
면접 함정
- ❌ "lastLocation이면 항상 위치를 얻는다" → 부팅 직후나 위치를 끈 기기에서는
null이다. - ❌ "백그라운드 위치는 권한만 받으면 계속 온다" → Doze와 배치 처리로 갱신이 크게 줄어든다.