🔥 Android 에서 Naver Map 에 현재 위치를 적용해보자.
지난 글에서 Android 에 Naver Map API 를 사용하여 지도를 띄우는 과정을 살펴보았다.
이어서 지도에 현재 위치를 적용하여 지도가 현재 위치 기준으로 띄워지도록 추가해보자.
하나의 지도는 뷰 요소와 인터페이스 요소로 구성됩니다. 뷰 요소는 화면에 지도를 나타내는 역할을 하며, MapFragment와 MapView가 여기에 해당합니다. 지도를 다루는 인터페이스 역할을 하는 인터페이스 요소는 NaverMap 클래스가 담당하며, 오버레이를 추가하고 상호작용하는 등 지도와 관련된 기능 대부분을 이 클래스에서 제공합니다. MapFragment 및 MapView는 개발자가 직접 생성할 수 있으나 NaverMap 객체는 오직 콜백 메서드를 이용해서 얻어올 수 있습니다.
위의 내용은 공식 문서의 내용이다. 지난 글에서 MapFragment 를 이용하여 지도를 나타내었으므로, 지도를 다루기 위해 API 에서 제공해주는 NaverMap 객체를 가져오도록 하자.
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var naverMap: NaverMap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.map_fragment_activity)
val fm = supportFragmentManager
val mapFragment = fm.findFragmentById(R.id.map) as MapFragment?
?: MapFragment.newInstance().also {
fm.beginTransaction().add(R.id.map, it).commit()
}
mapFragment.getMapAsync(this)
}
@UiThread
override fun onMapReady(naverMap: NaverMap) {
this.naverMap = naverMap
}
}
Naver Map 은 MapFragment 또는 MapView의 getMapAsync() 메서드로 OnMapReadyCallback을 등록하면 비동기로 NaverMap 객체를 얻을 수 있다고 나와있다. NaverMap 객체가 준비되면 onMapReady() 콜백 메서드가 호출된다. 위의 내용은 NaverMap 객체를 가져오는 예제이다.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
공식 문서에 따르면 네이버 지도 SDK 는 Google Play 서비스의 FusedLocationProviderClient와 지자기, 가속도 센서를 활용해 최적의 위치를 반환하는 구현체인 FusedLocationSource를 제공한다고 한다. 위치 정보를 사용할 때, FusedLocationSource를 사용하길 권장하고 있으므로 사용해보도록 하자.
implementation 'com.google.android.gms:play-services-location:21.0.1'
override fun onCreate(savedInstanceState: Bundle?) {
//...
// 위치 권한 요청
locationPermissionRequest.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION))
}
private val locationPermissionRequest = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
when {
permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
// Precise location access granted.
}
permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
// Only approximate location access granted.
} else -> {
// No location access granted
Toast.makeText(this, "위치 권한을 허용해주세요.", Toast.LENGTH_SHORT)
finish()
}
}
}
private lateinit var locationSource: FusedLocationSource
override fun onCreate(savedInstanceState: Bundle?) {
//...
locationSource = FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE)
//...
}
override fun onMapReady(naverMap: NaverMap) {
this.naverMap = naverMap
naverMap.locationSource = locationSource
naverMap.locationTrackingMode = LocationTrackingMode.Follow
}
companion object {
private const val LOCATION_PERMISSION_REQUEST_CODE = 1000
}
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
companion object {
private const val LOCATION_PERMISSION_REQUEST_CODE = 1000
}
private lateinit var locationSource: FusedLocationSource
private lateinit var naverMap: NaverMap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.map_fragment_activity)
// 위치 권한 요청
locationPermissionRequest.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION))
// FusedLocation
locationSource = FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE)
// naverMap 객체 획득을 위한 getMapAsync() 수행
val fm = supportFragmentManager
val mapFragment = fm.findFragmentById(R.id.map) as MapFragment?
?: MapFragment.newInstance().also {
fm.beginTransaction().add(R.id.map, it).commit()
}
mapFragment.getMapAsync(this)
}
@UiThread
override fun onMapReady(naverMap: NaverMap) {
// naverMap 객체 획득
this.naverMap = naverMap
// naverMap locationSource 에 FusedLocationSource 적용
naverMap.locationSource = locationSource
naverMap.locationTrackingMode = LocationTrackingMode.Follow
}
private val locationPermissionRequest = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
when {
permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
// Precise location access granted.
}
permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
// Only approximate location access granted.
} else -> {
// No location access granted
Toast.makeText(this, "위치 권한을 허용해주세요.", Toast.LENGTH_SHORT)
finish()
}
}
}
}
위치 설정 | 결과 |
---|---|