외로운 Nova의 작업실

안드로이드 앱 프로그래밍 - 38(사용자 위치 얻기) 본문

Programming/Kotlin - Android

안드로이드 앱 프로그래밍 - 38(사용자 위치 얻기)

Nova_ 2023. 3. 9. 16:21

- 구글 play 서비스의 위치 라이브러리

사용자의 위치를 얻으려면 gps, wifi, seluer 등을 이용해서 위치를 얻을 수 있습니다. 위치 제공자등을 선정할때는 아래와 같은 고려사항들이 있습니다. 

  • 전력을 적게 소비하는가
  • 정확도는 높은가
  • API가 간단한가
  • 부가기능을 제공하는가

일반적인 방법으로는 이런 것들을 하나하나 확인하고 검증해서 위치를 얻어야하기때문에 코드가 길어집니다. 따라서 대신 확인해주는 구글 play 서비스 라이브러리를 사용합니다.

 

- 퍼미션

매니페스트 파일에 아래와같이 선언해줍니다.

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

 

- 의존성

gradle 파일에 아래와 같이 선언해줍니다.

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

 

- 위치제공자 초기화

GoogleApiClient는 위치를 제공해주는 클라이언트입니다. 이를 초기화시켜줘야합니다. 초기화할때는 두가지 객체를 등록해줘야하는데, 하나는 GoogleApiCleint.ConnectionCallbasks이고 하나는 GoogleApiClient.OnConnectionFailedListenr 입니다. 이 두개를 만들어주고 아래와 같이 초기화해줍니다.

//init googleApiClient
        val connectionCallback = object: GoogleApiClient.ConnectionCallbacks{
            override fun onConnected(p0: Bundle?) {
                if (ActivityCompat.checkSelfPermission(
                        this@MainActivity,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                        this@MainActivity,
                        Manifest.permission.ACCESS_COARSE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    if(status != PackageManager.PERMISSION_GRANTED){
                        ActivityCompat.requestPermissions(this@MainActivity, arrayOf<String>("android.permission.ACCESS_FINE_LOCATION"), 100)
                    } else{
                        ActivityCompat.requestPermissions(this@MainActivity, arrayOf<String>("android.permission.ACCESS_COARSE_LOCATION"), 200)
                    }
                    return
                }
                providerClient.lastLocation.addOnSuccessListener(this@MainActivity
                ) { p0 ->
                    val latitude = p0?.latitude
                    val longitude = p0?.longitude
                    binding.latitude.text = latitude.toString()
                    binding.longitude.text = longitude.toString()

                }
            }

            override fun onConnectionSuspended(p0: Int) {
                TODO("Not yet implemented")
            }
        }

        val onConnectionFailedCallback = object: GoogleApiClient.OnConnectionFailedListener{
            override fun onConnectionFailed(p0: ConnectionResult) {
                TODO("Not yet implemented")
            }
        }

        val apiClient: GoogleApiClient = GoogleApiClient.Builder(this)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(connectionCallback)
            .addOnConnectionFailedListener(onConnectionFailedCallback)
            .build()

 

 

초기화를 시켜줬으니 위치 제공자를 아래와 같은 코드로 요청합니다.

//get Location Provider
apiClient.connect()

그러면 아래와같이 객체를 하나 생성해주면 그 객체로 위치제공자를 넘겨줍니다.

val providerClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)

이제 위치제공자를 받았으니 이 위치제공자를 가지고 위치를 받으면됩니다. 이때 onConncected 함수에 넣어주면됩니다. 아래는 메인액티비티.kt 전체 코드입니다.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        //get permission
        val status = ContextCompat.checkSelfPermission(this, "android.permission.ACCESS_FINE_LOCATION")
        val status2 = ContextCompat.checkSelfPermission(this, "android.permission.ACCESS_COARSE_LOCATION")
        if(status == PackageManager.PERMISSION_GRANTED && status2 == PackageManager.PERMISSION_GRANTED ){
            Log.d("log","permission granted")

        } else{
            if(status != PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(this, arrayOf<String>("android.permission.ACCESS_FINE_LOCATION"), 100)
        } else{
                ActivityCompat.requestPermissions(this, arrayOf<String>("android.permission.ACCESS_COARSE_LOCATION"), 200)
            }
    }

        //init FusedLocationProviderClient
        val providerClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)

        //init googleApiClient
        val connectionCallback = object: GoogleApiClient.ConnectionCallbacks{
            override fun onConnected(p0: Bundle?) {
                if (ActivityCompat.checkSelfPermission(
                        this@MainActivity,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                        this@MainActivity,
                        Manifest.permission.ACCESS_COARSE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    if(status != PackageManager.PERMISSION_GRANTED){
                        ActivityCompat.requestPermissions(this@MainActivity, arrayOf<String>("android.permission.ACCESS_FINE_LOCATION"), 100)
                    } else{
                        ActivityCompat.requestPermissions(this@MainActivity, arrayOf<String>("android.permission.ACCESS_COARSE_LOCATION"), 200)
                    }
                    return
                }
                providerClient.lastLocation.addOnSuccessListener(this@MainActivity
                ) { p0 ->
                    val latitude = p0?.latitude
                    val longitude = p0?.longitude
                    binding.latitude.text = latitude.toString()
                    binding.longitude.text = longitude.toString()

                }
            }

            override fun onConnectionSuspended(p0: Int) {
                TODO("Not yet implemented")
            }
        }

        val onConnectionFailedCallback = object: GoogleApiClient.OnConnectionFailedListener{
            override fun onConnectionFailed(p0: ConnectionResult) {
                TODO("Not yet implemented")
            }
        }

        val apiClient: GoogleApiClient = GoogleApiClient.Builder(this)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(connectionCallback)
            .addOnConnectionFailedListener(onConnectionFailedCallback)
            .build()



        //get Location Provider
        apiClient.connect()
    }
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
            Log.d("log","permission granted")
        } else{
            Toast.makeText(applicationContext,"해당 권한을 허용해주셔야 앱 사용이 가능합니다.", Toast.LENGTH_SHORT).show()
            ActivityCompat.requestPermissions(this, arrayOf<String>("android.permission.ACCESS_FINE_LOCATION"), 100)
            Log.d("log","permission denied")
        }
        if(grantResults[1] == PackageManager.PERMISSION_GRANTED){
            Log.d("log","permission granted")
        } else{
            Toast.makeText(applicationContext,"해당 권한을 허용해주셔야 앱 사용이 가능합니다.", Toast.LENGTH_SHORT).show()
            ActivityCompat.requestPermissions(this, arrayOf<String>("android.permission.ACCESS_COARSE_LOCATION"), 200)
            Log.d("log","permission denied")
        }
    }
}

아래는 메인 액티비티.xml 파일입니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/latitude"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="388dp"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/longitude"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toTopOf="@+id/latitude"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.891" />

</androidx.constraintlayout.widget.ConstraintLayout>

아래는 실행 화면입니다.

 

- 의존성 문제 해결

중복 의존성 문제가 있다면 아래 코드를 gradle.propertis 마지막에 추가해줍니다.

android.enableJetifier=true
Comments