앱에서 사용자의 위치를 추적하려면 3가지권한을 얻어야 한다.
android.permission.ACCESS_COARSE_LOCATION
도시에서 1블록 정도의 오차 수준을 가진다.
android.permission.ACCESS_FINE_LOCATION
최대한 정확한 위치에 접근하는 권한
android.permission.ACCESS_BACKGROUND_LOCATION
API레벨 29 이상에서 백그라운드 상태에서 위치에 접근하는 권한
API레벨 31 버전부터는 ACCESS_COARSE_LOCATION과 ACCESS_FINE_LOCATION을 같이 등록해 줘야 한다.
서비스에서 위치 접근은 아래와 같이 등록해야 한다.
<service
android:foregroundServiceType="location"
/>
// 위치 매니저 사용
val manager = getSystemService(LOCATION_SERVICE) as LocationManager
GPS
GPS 위성을 이용한다.
NetWork
이동 통신망을 이용한다.
Wifi
와이파이를 이용한다.
Passive
다른 앱에서 이용한 마지막 위치 정보를 이용한다.
// 모든 위치 제공자 알아보기
// 지금 사용할 수 있는 위치 제공자를 알아보려면 all Providers 대신 getProviders(true)를 사용한다.
var result = "All Providers : "
val providers = manager.allProviders
for (provider in providers) {
result += "$provider, "
}
위치를 한 번만 얻을 땐 getLastKnownLocation() 함수를 사용한다.
val location: Location? = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
location?.let {
// 위도
val latitude = location.latitude
// 경도
val longitude = location.longitude
// 정확도
val accuray = location.accuray
// 획득 시간
val time = location.time
}
계속 위치를 가져와야 한다면 LocationListener를 이용한다.
val listener: LocationListener = object: LocationListener {
// 새 위치를 가져오면 호출된다.
override fun onLocationChanged(location: Location) {}
// 위치 제공자가 이용할 수 있는 상황이면 호출된다.
override fun onProviderDisabled(provider: String) {}
// 위치 제공자가 이용할 수 없는 상황이면 호출된다.
override fun onProviderEnabled(provider: String) {}
}
manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10_000L, 10f, listener)
...
manager.removeUpdates(listener)
구글에서는 최적의 알고리즘으로 위치 제공자를 지정할 수 있도록 Fused Location Provider 라이브러리를 제공한다.
play 서비스 사용 선언
implementation 'com.google.android.gms:play=services:12.0.1'
Fused Location Provider의 핵심 클래스는 2가지이다.
FusedLocationProviderClient
위치 정보를 얻는다.
GoogleApiClient
위치 제공자 준비 등 다양한 콜백을 제공한다.
GoogleApiClient에서 위치 정보 제공자를 결정하면 이를 이용해서 FusedLocationProviderClient에서 위치를 가져오는 구조이다.
// GoogleApiClient 초기화
val connectionCallback = object: GoogleApiClient.ConnectionCallbacks {
// 위치 제공자를 사용할 수 있을 때 위치 획득
override fun onConnected(p0: Bundle?) {}
// 위치 제공자를 사용할 수 없을 때
override fun onConnectionSuspended(p0: Int) {}
val onConnectionFailedCallback = object : GoogleApiClient.OnConnectionFailedListener {
// 사용할 수 있는 위치 제공자가 없을 때
override fun onConnectionFailed(p0: ConnectionResult) {}
}
val apiClient: GoogleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(connectionCallback)
.addOnConnectionFailedListener(onConnectionFailedCallback)
.build()
// FusedLocationProviderClient 초기화
val providerClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
// 위치 제공자 요청
apiClient.connect()
connect() 함수를 호출하면 여러 가지 상황을 고려해 가장 알맞은 위치 제공자를 선택 후, onConnected() 함수를 호출해 준다.
따라서 onConnected() 함수에서 FusedLocationProviderClient의 getLastLocation() 함수만 호출해 주면 된다.
// 사용자 위치 얻기
override fun onConnected(p0: Bundle?) {
...
providerClient.getLastLocation().addOnSuccessListener(
this@FusedActivity,
object : OnSuccessListener<Location> {
override fun onSuccess(location: Location?) {
val latitude = location?.latitude
val longitude = location?.longitude
}
})
}