이 포스트는 2020년 5월과 8월 사이에 생성된 Android 네이티브 앱을 요약한 것입니다!
사용자 위치를 추적하는 이유는 무엇입니까?
- 사용자가 걷거나 운전하는 동안 방향을 찾거나 사용자의 위치를 추적하는 앱은 일정한 간격으로 장치의 위치를 확인해야 합니다.
이 앱에서는 사용자가 산책을 갈 때 사용자의 위치를 추적합니다.
위치 권한 설정
AndroidManifest.xml
<manifest ... >
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
...
</manifest>
위치 서비스 클라이언트 만들기
- 위치를 추적할 인스턴스를 만듭니다.
TrackingService.kt
class TrackingService: LifecycleService() {
lateinit var fusedLocationProviderClient: FusedLocationProviderClient
//...
override fun onCreate() {
super.onCreate()
//...
fusedLocationProviderClient = getFusedLocationProviderClient(this)
//...
}
위치 요청에 필요한 설정 제공
- LocationRequest 데이터 개체는 앱이 위치를 요청하거나 권한 업데이트를 받는 데 필요한 시스템 설정을 정의합니다.
- interval은 위치 요청에 필요한 수신 간격입니다.
- 가장 빠른 간격은 위치 요청에 필요한 가장 빠른 수신 간격입니다.
- 우선 순위는 위치 요청에 필요한 정확도를 설정합니다.
이 앱에서는 가장 정확한 위치를 요청하기 위해 PRIORITY_HIGH_ACCURACY를 설정했습니다.
TrackingService.kt
@SuppressLint("MissingPermission")
private fun updateLocationChecking(isTracking: Boolean) {
if (isTracking) {
if (TrackingUtility.hasLocationPermissions(this)) {
val locationRequest = LocationRequest.create().apply {
interval = LOCATION_UPDATE_INTERVAL
fastestInterval = FASTEST_LOCATION_INTERVAL
priority = PRIORITY_HIGH_ACCURACY
}
//...
}
} else {
//...
}
}
위치 요청
- 위도와 경도 LocationCallback.onLocationResult() 콜백 메소드에 포함됩니다. 위치 객체로 얻을 수 있습니다.
TrackingService.kt
val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
if (isTracking.value!!) {
locationResult?.locations?.let {
for (location in it) {
// Update UI with location data
}
}
}
}
}
위치 업데이트/정지
- 위치 요청 후 requestLocationUpdates()로 업데이트된 위치를 확인할 수 있습니다.
- 제거 위치 업데이트로 위치 업데이트를 중지할 수 있습니다.
앱은 사용자가 걷기 시작 버튼을 누르면 위치를 업데이트하고 사용자가 걷기 종료 버튼을 누르면 위치 요청을 중지합니다.
TrackingService.kt
@SuppressLint("MissingPermission")
private fun updateLocationTracking(isTracking: Boolean) {
if (isTracking) {
if (TrackingUtility.hasLocationPermissions(this)) {
//...
fusedLocationProviderClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
} else {
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
}
}
위치 권한 요청
build.gradle(:앱)
- easypermissions 라이브러리를 사용했습니다.
dependencies {
implementation 'com.vmadalin:easypermissions-ktx:1.0.0'
}
TrackingUtility.kt
- 객체로 싱글톤 클래스를 정의하여 위치 권한 확인 기능을 만들었습니다.
fun hasLocationPermissions(context: Context) =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
EasyPermissions.hasPermissions(
context,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
} else {
EasyPermissions.hasPermissions(
context,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
)
}
TrackingFragment.kt
- 걷기 시작 버튼을 눌렀을 때 위치 권한을 확인하세요.
class TrackingFragment : Fragment(R.layout.fragment_tracking), EasyPermissions.PermissionCallbacks {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//...
binding.btnStart.setOnClickListener {
if(TrackingUtility.hasLocationPermissions(requireContext())){
sendCommandToService(ACTION_START_OR_RESUME_SERVICE)
}else {
requestPermissions()
}
}
//...
}
// ...
private fun requestPermissions() {
if (TrackingUtility.hasLocationPermissions(requireContext())) { // 권한이 있는 경우에는 권한을 요청하지 않습니다.
return
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
EasyPermissions.requestPermissions(
this,
"'어야가자' 이용을 위해 위치 권한을 '허용'으로 선택해주세요.",
Constants.REQUEST_CODE_LOCATION_PERMISSION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
} else {
EasyPermissions.requestPermissions(
this,
"'어야가자' 이용을 위해 위치 권한을 '허용'으로 선택해주세요.",
Constants.REQUEST_CODE_LOCATION_PERMISSION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
)
}
}
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
TODO("Not yet implemented")
}
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
AppSettingsDialog.Builder(this).build().show()
} else {
requestPermissions()
}
}
}
UI 업데이트를 위한 변수(trackingLocation) 생성
이 앱에서는 UI 업데이트를 위한 데이터를 관찰하여 위치를 표시합니다.
TrackingService.kt
companion object {
//...
val trackingLocation = MutableLiveData<LatLng>()
}
//...
val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
if (isTracking.value!!) {
locationResult?.locations?.let {
for (location in it) {
var locationUpdate = LatLng(location.latitude!!, location.longitude!!)
trackingLocation.postValue(locationUpdate)
}
}
}
}
}
TrackingFragment.kt
private fun subscribeToObservers() {
//...
TrackingService.trackingLocation.observe(viewLifecycleOwner, { trackingLocation ->
map?.animateCamera(CameraUpdateFactory.newLatLngZoom(trackingLocation, MAP_ZOOM))
})
}