사용자 위치 얻기

2024. 7. 31. 11:05[개발]/Kotlin 활용 앱 개발

# 위치 접근 권한

- 사용자 위치 추적을 위한 3가지 권한 필요

1) android.permission.ACCESS_COARSE_LOCATION: 와이파이/모바일 데이터를 사용해 기기의 위치에 접근하기 위한 권한(도시에서 1블록 정도의 오차 수준)

2) android.permission.ACCESS_FINE_LOCATION: 위성/와이파이/모바일 데이터 등을 이용할 수 있는 위치 제공자를 사용해 최대한 정확한 위치에 접근하기 위한 권한

3) android.permission.ACCESS_BACKGROUND_LOCATION: 안드로이드 10 이상에서 백그라운드 상태에서 위치에 접근하기 위한 권한

 

# 권한 설정

- manifest에 권한 추가 필요

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <!-- 정밀 위치 권한 요청 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    ...
</manifest>

 

# 권한 요청

- 런타임 시 앱은 유저에게 권한을 요청해야 함

- 안드로이드 6.0(API 레벨 23) 이상에서는 유저가 앱을 사용하는 동안 권한을 부여하거나 취소할 수 있음

// ACCESS_FINE_LOCATION 권한을 요청하고 획득하는 예제 코드
class MainActivity : AppCompatActivity() {

    companion object {
        private const val PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 100
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        requestLocationPermission()
    }

	// 앱에 위치 권한이 있는지 확인
    private fun requestLocationPermission() {
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // 권한이 없을 경우, 사용자에게 요청
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                PERMISSION_REQUEST_ACCESS_FINE_LOCATION
            )
        } else {
            // 권한이 이미 있을 경우, 위치 정보를 사용할 수 있음
            getLocation()
        }
    }

	// ActivityCompat.requestPermissions 메서드를 통해 권한을 요청한 결과를 onRequestPermissionResult 콜백 메서드에서 처리
   override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        when (requestCode) {
            PERMISSION_REQUEST_ACCESS_FINE_LOCATION -> {
                if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    // 권한이 부여되면 위치 정보를 사용할 수 있음
                    getLocation()
                } else {
                    // 권한이 거부되면, 기능 사용 불가
                }
                return
            }
        }
    }

    private fun getLocation

 

# 위치 데이터 얻는 방법 ① - 플랫폼 API의 위치 매니저

- LocationManager라는 시스템 서비스 이용

val manager = getSystemService(LOCATION_SERVICE) as LocationManager

 

1) 위치 제공자 지정

- GPS
- Network(이동 통신망)

- Wifi

- Passive(다른 앱에서 이용한 마지막 위치 정보)

 

2) 현재 기기에 있는 위치 제공자 정보 파악

- LocationManager의 allProviders 프로퍼티 이용

var result = "All Providers : "
val providers = manager.allProviders
for (provider in providers) {
		result += " $provider. "
}
Log.d("maptest", result)  // All Providers : passive, gps, network..

 

3) 현재 기기에서 지금 사용할 수 있는 위치 제공자 정보 파악

- LocationManager의 getProviders 함수 이용

result = "Enabled Providers : "
val enabledProviders = manager.getProviders(true)
for (provider in enabledProviders) {
		result += " $provider. "
}
Log.d("maptest", result)  // Enabled Providers : passive, gps, network..

 

4) 위치 정보 얻기(1회)

- LocationManager의 getLastKnownLocation() 함수 이용

- 포함 데이터: 위치의 정확도(getAccuracy()), 위도(getLatitude()), 경도(getLongitude()), 획득 시간(getTime()) 등

if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            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")
            }
        }

 

5) 위치 정보 얻기(지속적으로)

- LocationListener 이용

- onLocationChanged(): 새로운 위치 가져오면 호출됨

- onProviderEnabled(): 위치 제공자가 이용 가능한 상황이면 호출

- onProviderDisabled(): 위치 제공자가 이용 불가한 상황이면 호출

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)
        // (.. 생략 ..) //
        manager.removeUpdates(listener)

 

# 위치 데이터 얻는 방법 ② -구글 Play 서비스의 위치 라이브러리

- 구글에서 전력을 적게 소비하고 정확도가 높고, API가 간단하고, 부가 기능을 제공하고, 대부분의 안드로이드 기기를 지원하는 'Fused Location Provider' 라이브러리 제공함

 

1) gradle에 사용 선언

implementation 'com.google.android.gms:play-services:12.0.1'

 

2) 클래스 설정

- FusedLocationProviderClient: 위치 정보를 가져옴

- GoogleApiClient: 위치 제공자 준비 등 다양한 콜백을 제공(위치 제공자를 사용할 수 있을 때 / 사용할 수 없을 때 / 사용에 실패했을 때 등) / GoogleApiClient.ConnectionCallbacks, GoogleApClient.OnConnectionFailedListener 인터페이스를 구현할 객체를 지정

- FusedLocationProviderClient, GoogleApiClient 클래스를 초기화하는 코드를 작성

// 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)

 

3) GoogleApiClient 객체에 위치 제공자를 요청

apiClient.connect()

 

4) onConnected() 함수에서 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()
        }
    }

 

'[개발] > Kotlin 활용 앱 개발' 카테고리의 다른 글

Retrofit 개념  (0) 2024.07.31
Google Map 가져오기  (0) 2024.07.31
데이터 저장 - Room  (0) 2024.07.31
데이터 저장 - SharePreferences  (0) 2024.07.31
Compose - 함수 / UI 구성  (0) 2024.07.30