위치 접근 권한
사용자의 위치를 추적하기 위한 3가지 권한
- android.permission.ACCESS_COARSE_LOCATION: 와이파이나 모바일 데이터(또는 둘 다)를 사용해 기기의 위치에 접근하는 권한입니다. 도시에서 1블록 정도의 오차 수준입니다.
- android.permission.ACCESS_FINE_LOCATION: 위성, 와이파이, 모바일 데이터 등 이용할 수 있는 위치 제공자를 사용해 최대한 정확한 위치에 접근하는 권한입니다.
- android.permission.ACCESS_BACKGROUND_LOCATION: 안드로이드 10(API 레벨 29) 이상에서 백그라운드 상태에서 위치에 접근하는 권한입니다.
- 안드로이드 권한 설정 및 획득 방법권한 설정앱이 위치 정보에 접근하려면, 먼저 AndroidManifest.xml 파일에 위치 권한을 추가해야 합니다.
권한 설정
매니페스트에 권한 추가
앱이 위치 정보에 접근하려면, 먼저 AndroidManufest 파일에 위치 권한을 추가해야 합니다.
<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()
}
}
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
위 코드에서 requesLocationPermission함수는 먼저 앱에 위치 권한이 있는지 확인합니다. 권한이 없다면 ActivityCompat.requestPermissions메소드를 사용하여 권한을 요청하고, 결과는 onRequestPermissionsResult 콜백 메소드에서 처리합니다. 사용자가 권한을 부여하면 getLocation메소드를 호출하여 위치 정보를 사용할 수 있습니다.
플랫폼 API의 위치 매니저
- 사용자의 위치를 얻을 때는 LocationManager라는 시스템 서비스를 이용
val manager = getSystemService(LOCATION_SERVICE) as LocationManager
위치 매니저 사용
- 위치 제공자 지정하기
- GPS: GPS 위성을 이용합니다.
- Network: 이동 통신망을 이용합니다.
- Wifi: 와이파이를 이용합니다.
- Passive: 다른 앱에서 이용한 마지막 위치 정보를 이용합니다.
- 현재 기기에 어떤 위치 제공자가 있는지를 알고 싶다면 LocationManager의 allProviders 프로퍼티를 이용
var result = "All Providers : "
val providers = manager.allProviders
for (provider in providers) {
result += " $provider. "
}
Log.d("maptest", result)
모든 위치 제공자 알아보기
지금 사용할 수 있는 위치 제공자를 알아보려면 getProviders() 함수를 이용
result = "Enabled Providers : "
val enabledProviders = manager.getProviders(true)
for (provider in enabledProviders) {
result += " $provider. "
}
Log.d("maptest", result)
지금 사용할 수 있는 위치 제공자 알아보기
- 위치정보얻기
- LocationManager의 getLastKnownLocation() 함수를 이용
- Location은 위치의 정확도, 위도, 경도, 획득 시간 등의 데이터를 포함
- 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")
}
}
위치 한 번만 가져오기
- 계속 위치를 가져와야 한다면 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라는 라이브러리를 제공
implementation 'com.google.android.gms:play-services:12.0.1'
구글 play 서비스 사용 선언
- Fused Location Provider에서 핵심 클래스
- FusedLocationProviderClient: 위치 정보를 얻습니다.
- GoogleApiClient: 위치 제공자 준비 등 다양한 콜백을 제공합니다.
- GoogleApi Client에서는 GoogleApiClient.ConnectionCallbacks와 GoogleApiClient.OnConnection FailedListener 인터페이스를 구현한 객체를 지정
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()
GoogleApiClient 초기화
FusedLocationProviderClient 초기화
val providerClient = LocationServices.getFusedLocationProviderClient(this)
GoogleApiClient 객체에 위치 제공자를 요청
apiClient.connect()
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()
}
}
구글 지도 앱 만들기
https://teamsparta.notion.site/11-2-def99f594e3c4b86a3860d14a88ba0ab