TodayILearned/Android&Kotlin
사용자 위치 얻기
YJ_ILY
2023. 9. 14. 16:32
- 지도를 이용해서 서비스를 제공하는 앱을 만들 경우 필요
- 네이버맵, 다음맵 등 다양한 플랫폼에서 제공하는 맵을 사용
- 맵을 사용하려면 내 단말을 통해 위치를 얻어와야 함
- 위치를 얻으려면 권한이 필요
사용자의 위치를 추적하기 위한 3가지 권한
- android.permission.ACCESS_COARSE_LOCATION :
- 와이파이나 모바일 데이터를 사용해 기기의 위치에 접근하는 권한
- 도시에서 1블록 정도의 오차 수준
- android.permission.ACCESS_FINE_LOCATION :
- 위성, 와이파이, 모바일 데이터 등 이용할 수 있는 위치 제공자를 사용해 최대한 정확한 위치에 접근하는 권한
- 많이 사용하는 접근 권한
- android.permission.ACCESS_BACKGROUND_LOCATION :
- 안드로이드 10(API 레벨 29) 이상에서 백그라운드 상태에서 위치에 접근하는 권한
플랫폼 API의 위치 매니저를 이용해 사용자의 위치를 얻는 방법
- LocationManager 라는 시스템 서비스 이용
- LocationManager는 모든 스마트폰의 프레임워크 안에 들어있음
val manager = getSystemService(LOCATION_SERVICE) as LocationManager
- 위치 제공자 지정하기 (위치를 어디서 받을지)
- GPS, Network, Wifi, Passive(다른 앱에서 이용한 마지막 위치 정보 이용)
위치 정보를 받는 방법
- 현재 기기에 어떤 위치 제공자가 있는지 알아보기
val result = "All Providers :"
//allProviders 프로퍼티 이용해 현재 기기에 어떤 위치 제공자가 있는지 알 수 있음
val providers = manager.allProviders
for (provider in providers) {
result += "$provider."
}
Log.d("maptest", result)
* 현재 기기에 어떤 위치 제공자가 있는지 알고싶다면?
LocationManager의 allProviders 프로퍼티 이용
- 지금 사용할 수 있는 위치 제공자를 알아보기 (getProviders() 함수)
result = "Enabled Providers :"
val enabledProviders = manager.getProviders(true)
for (provider in enabledProviders) {
result += "$provider."
}
Log.d("maptest", result)
- 위치 정보 얻기 (getLastKnownLocation() 함수)
// Permission이 있는지 먼저 체크
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
// Permission이 획득이 되어있다면 로케이션 매니저를 가져오기
val location: Location? = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
location?.let{
val latitude = location.latitude
val longitude = location.longitude
val accuracy = location.accuracy
val time = location.time
Log.d("map_test", "$latitude, $location, $accuracy, $time")
}
}
* getAccuracy() : 정확도
* getLatitude() : 위도
* getLongitude() : 경도
* getTiem() : 획득 시간
- 계속해서 위치를 가져와야 한다면 LocationListener를 이용(예: 내비게이션)
//
val listener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
Log.d("map_test,","${location.latitude}, ${location.longitude}, ${location.accuracy}")
}
}
// 지정해주어야 함
manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10_000L, 10f, listener)
// (.. 생략 ..) //
// 업데이트가 끝나면 removeUpdates 사용해서 꼭 삭제해줘야함
manager.removeUpdates(listener)
* onLocationChanged() : 새로운 위치를 가져오면 호출됨
* onProviderEnabled(): 위치 제공자가 이용할 수 있는 상황이면 호출됨
* onProviderDisabled() : 위치 제공자가 이용할수 없는 상황이면 호출됨
구글 Play 서비스의 위치 라이브러리
- 편리하고 정확도가 더 높음
- 최적의 알고리즘으로 위치 제공자를 지정할 수 있도록 Fused Location Provider 라이브러리를 제공
- gradle 설정 파일에 아래와 같은 코드를 추가해야 사용 가능
implementation 'com.google.android.gms:play-services:12.0.1'
위치 제공자를 지정할 때 고려할 사항
- 전력을 적게 소비하는가
- 정확도는 높은가
- API가 간단한가
- 부가 기능을 제공하는가
- 대부분 안드로이드 기기를 지원하는가
Fused Location Provider
- FusedLocationProviderClient : 위치 정보를 얻음
- GoogleApiClient : 위치 제공자 준비 등 다양한 콜백 제공
val connectionCallback = object: GoogleApiClient.ConnectionCallbacks{
override fun onConnected(p0: Bundle?) {
// 위치 제공자를 사용할 수 있을 때
// 위치 획득
}
override fun onConnectionSuspended(p0: Int) {
// 위치 제공자를 사용할 수 없을 때
}
}
val onConnectionFailCallback = object : GoogleApiClient.OnConnectionFailedListener{
override fun onConnectionFailed(p0: ConnectionResult) {
// 사용할 수 있는 위치 제공자가 없을 때
}
}
// 선언할 때
val apiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(connectionCallback)
.addOnConnectionFailedListener(onConnectionFailCallback)
.build()
FusedLocationProviderClient 초기화
val providerClient = LocationServices.getFusedLocationProviderClient(this)
GoogleApiClient 객체에 위치 제공자를 요청
apiClient.connect()
- onConnect() 함수에서 FusedLocationProviderClient의 getLastLocation() 함수 호출
// 위치 제공자를 사용할 수 있는 상황일 때
override fun onConnected(p0: Bundle?) {
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
=== PackageManager.PERMISSION_GRANTED){
providerClient.lastLocation.addOnSuccessListener(
this@MainActivity,
object: OnSuccessListener<Location> {
override fun onSuccess(p0: Location?) {
p0?.let {
val latitude = p0.latitude
val longitude = p0.longitude
Log.d("map_test", "$latitude, $longitude")
}
}
}
)
apiClient.disconnect()
}
}