[android] 내 위치 정보 가져오기

Pyo·2024년 8월 26일
0

이론적인 부분들을 공부하면서 본격적으로 안드로이드를 이용하여 앱을 만들고 있다. 앱을 만들다 보면 기기의 위치가 필요한 경우가 많을것 같아서 위치를 기반으로 상세 주소를 가져오는 방법을 정리해 보려고 한다.

사용방법

  1. androidMainfest.xml - permission 추가

우선 permission 을 추가해 주어야 한다. 두 권한 모두 위치 권한을 요청하기 위한 권한으로, ACCESS_COARSE_LOCATION은 대략적인 위치 , ACCESS_FINE_LOCATION은 더 자세한 위치를 요청하는 권한이다.

  1. 라이브러리 추가

권한을 추가 했다면 다음은 라이브러리를 추가해야 한다. Google Play 서비스의 위치 관련 API를 사용하기 위한 라이브러리이다.

    implementation ("com.google.android.gms:play-services-location:21.0.1")
  1. 소스 코드

우선 전체적인 소스 코드로, 아래에서 기능별로 조금더 자세히 정리해보겠다.

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private lateinit var locationTextView: TextView
    private lateinit var getLocationButton: Button

    private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            val fineLocationGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true
            val coarseLocationGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true
            if (fineLocationGranted || coarseLocationGranted) {
                checkLocationSettings()
            } else {
                locationTextView.text = "위치 권한이 필요합니다."
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this,R.layout.activity_main)

        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        locationTextView = binding.locationTextView
        getLocationButton = binding.getLocationButton

        getLocationButton.setOnClickListener {
            if (hasLocationPermissions()) {
                checkLocationSettings()
            } else {
                requestPermissionLauncher.launch(
                    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
                )
            }
        }
    }

    private fun hasLocationPermissions(): Boolean {
        val fineLocationPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
        val coarseLocationPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
        return fineLocationPermission && coarseLocationPermission
    }

    private fun checkLocationSettings() {
        val locationMode = Settings.Secure.getInt(
            contentResolver,
            Settings.Secure.LOCATION_MODE,
            Settings.Secure.LOCATION_MODE_OFF
        )

        if (locationMode == Settings.Secure.LOCATION_MODE_OFF) {
            locationTextView.text = "위치 서비스가 비활성화되어 있습니다. 위치 서비스를 활성화해주세요."
            val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
            startActivity(intent)
        } else {
            getCurrentLocation()
        }
    }

    private fun getCurrentLocation() {
        if (!hasLocationPermissions()) {
            locationTextView.text = "위치 권한이 없습니다."
            return
        }

        val locationRequest = LocationRequest.create().apply {
            interval = 10000
            fastestInterval = 5000
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }

        val locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                locationResult ?: return
                val location = locationResult.lastLocation
                if (location != null) {
                    val latitude = location.latitude
                    val longitude = location.longitude
                    locationTextView.text = "위도: $latitude, 경도: $longitude"

                    // Convert coordinates to address
                    convertCoordinatesToAddress(latitude, longitude)
                } else {
                    locationTextView.text = "위치를 가져올 수 없습니다."
                }
            }
        }

        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, mainLooper)
            .addOnFailureListener { e ->
                locationTextView.text = "위치 요청 실패: ${e.message}"
            }
    }

    private fun convertCoordinatesToAddress(latitude: Double, longitude: Double) {
        val geocoder = Geocoder(this)
        try {
            val addresses = geocoder.getFromLocation(latitude, longitude, 1)
            if (addresses != null && addresses.isNotEmpty()) {
                val address = addresses[0]
                val addressText = buildString {
                    append("주소: ${address.getAddressLine(0)}\n")
                }
                locationTextView.text = addressText
            } else {
                locationTextView.text = "주소를 가져올 수 없습니다."
            }
        } catch (e: Exception) {
            Log.e("GeocoderError", "주소 변환 실패: ${e.message}")
            locationTextView.text = "주소 변환 실패"
        }
    }
}

위치 권한 체크 및 설정

앱의 권한을 처리하는 함수로 앱의 위치 서비스가 비활성화 되어 있다면 설정화면으로 이동하여 위치 서비스를 활성화 하는 함수 이다.

  private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            val fineLocationGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true
            val coarseLocationGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true
            if (fineLocationGranted || coarseLocationGranted) {
                checkLocationSettings()
            } else {
                locationTextView.text = "위치 권한이 필요합니다."
            }
        }
        
        
	 private fun hasLocationPermissions(): Boolean {
        val fineLocationPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
        val coarseLocationPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
        return fineLocationPermission && coarseLocationPermission
    }

    private fun checkLocationSettings() {
        val locationMode = Settings.Secure.getInt(
            contentResolver,
            Settings.Secure.LOCATION_MODE,
            Settings.Secure.LOCATION_MODE_OFF
        )

        if (locationMode == Settings.Secure.LOCATION_MODE_OFF) {
            locationTextView.text = "위치 서비스가 비활성화되어 있습니다. 위치 서비스를 활성화해주세요."
            val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
            startActivity(intent)
        } else {
            getCurrentLocation()
        }
    }

위치 정보 (위도,경도) 가져 오기

이제 본격적으로 앱의 위도,경도를 구하는 함수이다. 위치서비스가 활성화 되어 있다면, Google Play 서비스의 FusedLocationProviderClient를 위치 요청을 수행하여 현재 위치에 데이터를 수신하는 콜백함수이다.

 private fun getCurrentLocation() {
        if (!hasLocationPermissions()) {
            locationTextView.text = "위치 권한이 없습니다."
            return
        }

        val locationRequest = LocationRequest.create().apply {
            interval = 10000
            fastestInterval = 5000
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }

        val locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                locationResult ?: return
                val location = locationResult.lastLocation
                if (location != null) {
                    val latitude = location.latitude
                    val longitude = location.longitude
                    locationTextView.text = "위도: $latitude, 경도: $longitude"

                    // Convert coordinates to address
                    convertCoordinatesToAddress(latitude, longitude)
                } else {
                    locationTextView.text = "위치를 가져올 수 없습니다."
                }
            }
        }

        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, mainLooper)
            .addOnFailureListener { e ->
                locationTextView.text = "위치 요청 실패: ${e.message}"
            }
    }

위치 정보 주소로 변경

위치에 대한 정보(위도,경도)를 기반으로 Geocoder 클래스를 사용하여 실제 주소로 변환하여 화면에 보여주는 함수 이다.

  private fun convertCoordinatesToAddress(latitude: Double, longitude: Double) {
        val geocoder = Geocoder(this)
        try {
            val addresses = geocoder.getFromLocation(latitude, longitude, 1)
            if (addresses != null && addresses.isNotEmpty()) {
                val address = addresses[0]
                val addressText = buildString {
                    append("주소: ${address.getAddressLine(0)}\n")
                }
                locationTextView.text = addressText
            } else {
                locationTextView.text = "주소를 가져올 수 없습니다."
            }
        } catch (e: Exception) {
            Log.e("GeocoderError", "주소 변환 실패: ${e.message}")
            locationTextView.text = "주소 변환 실패"
        }
    }

실행 화면

이렇게 현재 내기기의 위치를 받아오는 과정에 대해 알아보았다. 끝 !

0개의 댓글

관련 채용 정보