개발 노트/Kotlin

[Android/Kotlin] Google Map API 사용해서 구글 지도맵 만들기

juwon2 2024. 5. 1. 00:27

# GoogleCloud에서 사용자 인증키 만들기

GoogleCloud에 접속하여 구글 계정으로 로그인한다

 

프로젝트가 생성되어있지 않다면 새프로젝트를 눌러서, 이름을 적고 새 프로젝트를 생성해준다

 

 

 

API 및 서비스 -> 사용자 인증정보 클릭

 

 

 

사용자 인증정보 만들기 -> API 키 클릭

 

 

API 키가 생성되었다 (지금은 API키 제한을 안걸어두었지만, 제한을 걸어서 사용해줄 수도 있다)

https://developers.google.com/maps/documentation/android-sdk/start?hl=ko#enable-api-sdk

 

Android용 Maps SDK 빠른 시작  |  Google for Developers

지금 바로 Android 앱용 Google 지도 프로젝트를 새로 시작해 보세요. 다음과 같이 SDK 설치부터 앱 빌드 및 실행에 이르기까지 필요한 모든 것을 찾을 수 있습니다.

developers.google.com

 

요기 링크 들어가서 2단계부분을 누르면 위와같은 화면이 뜰텐데 사용설정을 눌러서 정보들을 입력해준다 (주소, 카드번호 등 입력해야함)

 

 

 

 

 

# 구글 지도맵 만들기

build.gradle - 모듈버전에 아래와 같이 추가

plugins {
	...
    alias(libs.plugins.playMap)
}
dependencies {
	
   	...

    implementation (libs.play.services.maps)
    implementation (libs.play.services.location)
}

build.gradle.kt - module

 

 

build.gradle - 프로젝트 버전에도 아래와같이 추가

plugins {
	...
    alias(libs.plugins.playMap) apply false
}

build.gradle.kt - project

 

 

libs.versions.toml 에 들어가서 아래와같이 추가

[versions]
...
playMaps = "2.0.1"
playServicesLocation = "21.2.0"
playServicesMaps = "18.2.0"

[libraries]
...
play-services-location = { module = "com.google.android.gms:play-services-location", version.ref = "playServicesLocation" }
play-services-maps = { module = "com.google.android.gms:play-services-maps", version.ref = "playServicesMaps" }

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

playMap = {id = 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin',  version.ref = "playMaps"}

libs.versions.toml

 

매니페스트 파일에도 permission과 google-map api 추가

android: value 부분에는 아까 생성했던 API키를 복사해서 붙여넣어준다

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!--지도 사용설정을 위한 permission등록-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MapExample"
        tools:targetApi="31">


        <!--구글 지도 API를 이용하는 키를 등록-->
        <uses-library android:name="org.apache.http.legacy" android:required="true"/>
        <meta-data android:name="com.google.android.maps.v2.API_KEY"
            android:value="== Google Cloud에서 생성한 API키 입력!! ==="/>
        <meta-data android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>


        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Manifest.xml

 

 

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mapView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.google.android.gms.maps.SupportMapFragment"/>

activity_main.xml

 

 

 

// OnMapReadyCallback를 상속받으면 onMapReady를 필수적으로 오버라이딩 해줘야함
class MainActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mGoogleMap: GoogleMap

    // 위치 서비스가 gps를 사용해서 위치를 확인
    lateinit var fusedLocationClient: FusedLocationProviderClient

    // 위치 값 요청에 대한 갱신 정보를 받는 변수
    lateinit var locationCallback: LocationCallback

    // 권한요청
    lateinit var locationPermission: ActivityResultLauncher<Array<String>>


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 권한 체크
        locationPermission = registerForActivityResult(
            ActivityResultContracts.RequestMultiplePermissions()){ results ->
            // 권한이 있다면
            if(results.all{it.value}){
                // mapView에 연결
                // SupportMapFragment 를 찾은 후 getMapAsync() 를 호출해서 안드로이드에 구글 지도를 그려달라는 요청함
                (supportFragmentManager.findFragmentById(R.id.mapView) as SupportMapFragment)!!.getMapAsync(this)
            }else{ //문제가 발생했을 때
                Toast.makeText(this,"권한 승인이 필요합니다.",Toast.LENGTH_LONG).show()
            }
        }

        //권한 요청
        locationPermission.launch(
            arrayOf(
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION
            )
        )
    }


    // 지도 객체를 이용할 수 있는 상황이 될 때 호출 (Map이 준비가되면 OnMapReadyCallback에 의해서 이 함수가 바로 콜백됨)
    // 파라미터로 준비된 GoogleMap 을 전달
    // 메서드 안에서 미리 선언된 mMap 프로퍼티에 GoogleMap 을 저장해두면 액티비티 전체에서 맵을 사용할 수 있음
    override fun onMapReady(p0: GoogleMap) {

        val seoul = LatLng(37.566610, 126.978403)
        mGoogleMap = p0
        mGoogleMap.mapType = GoogleMap.MAP_TYPE_NORMAL // default 노말 생략 가능
        mGoogleMap.apply {
            val markerOptions = MarkerOptions()
            markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
            markerOptions.position(seoul)
            markerOptions.title("서울시청")
            markerOptions.snippet("Tel:01-120")
            addMarker(markerOptions)
        }

        // 위치정보 받아옴
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        updateLocation()
    }

    fun updateLocation(){

        val locationRequest = LocationRequest.create().apply {
            interval = 1000
            fastestInterval = 500
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }

        locationCallback = object : LocationCallback(){
            //1초에 한번씩 변경된 위치 정보가 onLocationResult 으로 전달된다.
            override fun onLocationResult(locationResult: LocationResult) {
                locationResult?.let{
                    for (location in it.locations){
                        Log.d("위치정보",  "위도: ${location.latitude} 경도: ${location.longitude}")
                        setLastLocation(location) //계속 실시간으로 위치를 받아오고 있기 때문에 맵을 확대해도 다시 줄어든다.
                    }
                }
            }
        }
        //권한 처리
        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,
            Looper.myLooper()!!
        )
    }

    fun setLastLocation(lastLocation: Location){
        val LATLNG = LatLng(lastLocation.latitude,lastLocation.longitude)

        val makerOptions = MarkerOptions().position(LATLNG).title("나 여기 있어용~")
        val cameraPosition = CameraPosition.Builder().target(LATLNG).zoom(15.0f).build()

        mGoogleMap.addMarker(makerOptions)
        mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
    }
}

MainActivity.kt

 

 

# 실행 결과

 

 

 

 

 

 

 

 

# 참고자료

https://developers.google.com/maps/documentation/android-sdk/start?hl=ko#enable-api-sdk

https://eonhwa-theme.tistory.com/90

https://velog.io/@krrong/Android-%EA%B5%AC%EA%B8%80-%EB%A7%B5-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0

https://developers.google.com/maps/documentation/android-sdk/marker?hl=ko