본문 바로가기
깡샘 코틀린

19-2 구글 지도 활용하기

by 농농씨 2023. 7. 13.

안드로이드 앱에서 지도를 출력하려면 먼저 지도 서비스를 제공하는 업체를 선정해야 한다. 지도 서비스 제공 업체로는 구글, 네이버, 카카오 등이 대표적이며 이곳에서 제공하는 API를 이용하면 지도를 출력할 수 있다. 이 책에서는 구글 지도를 이용할 것이다.

 

 

지도 사용 설정하기

구글 지도를 이용하려며 빌드 그래들과 매니페스트 파일, 구글 개발자 콘솔 등에 몇 가지 설정을 해야 한다. 지금부터 차례대로 살펴볼 것이다. 먼저 빌드 그래들의 dependencies 항목에 다음과 같이 선언한다.

// 구글 지도 사용 선언
implementation 'com.google.android.gms:play-services:12.0.1'

그리고 매니페스트에 다음과 같은 퍼미션을 등록한다. 구글 지도는 구글 서버에서 전송되는 데이터이므로 네트워크 통신이 필요하다. 따라서 18장에서 살펴본 네트워크 통신 관련 권한을 등록해야 한다.

// 퍼미션 등록
<uses-permission android:name="android.permission.INTERNET" />

그리고 다음처럼 구글 지도 API를 이용하는 키를 등록해야 한다.

// 구글 지도 API 키 등록
<application ... 생략 ...>
    <uses-library android:name="org.apache.http.legacy" android:required="false" />
    // apache 라이브러리를 이용한 HTTP 통신을 허용하는 설정을 키로 등록
    <meta-data android:name="com.google.android.maps.v2.API_KEY"
        android:value="###구글 지도 API 키 등록###" /> 
        // 여기에 구글 개발자 콘솔에서 얻은, 지도 API 키를 등록한다.
    <meta-data android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
        // play-services 라이브러리의 버전 정보
</application>

<uses-library> 부분에 선언한 org.apache.http.legacy는 안드로이드 앱에서 apache 라이브러리를 이용한 HTTP 통신을 허용하는 설정이다. apache 라이브러리는 원래 안드로이드 플랫폼 API 였지만 안드로이드 9버전부터는 앱에서 기본으로 이용할 수 없다. 그런데 집필 시점의 play-services 라이브러리에서 지도 데이터를 가져오려고 서버와 연동할 때 apache 라이브러리를 사용하므로 위같이 선언했다.

이어서 <meta-data>를 2개 선언했는데 gms.version은 play-services 라이브러리의 버전이므로 value 값에 @integer/google_play_services_version을 지정한다. 그리고 maps.v2.API_KEY의 value값에는 구글 개발자 콘솔에서 얻은 지도 API 키를 등록한다.

 

 

구글 개발자 콘솔에서 지도 API 키 얻기

구글 지도를 앱의 화면에 출력하려면 구글 개발자 콘솔에서 API 키를 얻어야 한다. 구글 개발자 콘솔(console.cloud.google.com)에 접속해 프로젝트를 생성하고 사용자 인증 정보를 만들면 지도 API 키를 발급해 준다. 자세한 절차는 19-3절에서 알아보자.

 

구글 개발자 콘솔에서 얻은 지도 API 키를 매니페스트 파일에 등록한다. 앞에서 살펴본 것처럼 maps.v2.API_KEY 이름으로 등록한 <meta-data> 태그의 value 속성값으로 지정해주면 된다.

// 지도 API 키 등록하기
<meta-data android:name="com.google.android.maps.v2.API_KEY"
    android:value="###구글 지도 API 키 등록###" /> // value 속성값에 지도 키 등록

 

 

레이아웃 XML

play-services 라이브러리에서 지도는 프래그먼트로 제공하므로 지도를 출력할 화면에 프래그먼트를 등록한다.

// 지도 프래그먼트 등록
<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" // 주목~
    />

 

 

지도 제어하기

앞에서 살펴본 방법만으로도 화면에 지도를 출력할 수 있지만 기본으로 보이는 위치는 아프리카 대륙이다. 따라서 사용자의 위치를 중심으로 지도를 보여주고 마커를 표시하거나 지도에서 사용자 이벤트를 처리하려면 지도를 제어하는 코드를 작성해야 한다.

 

지도의 중심 이동하기

지도가 표시하는 지점을 이동하려면 먼저 지도를 출력하는 뷰 객체를 얻어야 한다. play-services 라이브러리가 제공하는 프래그먼트에서 GoogleMap 클래스가 실제 지도를 출력하는 뷰이다.

// 지도 뷰 객체 얻기
Class MapActivity : AppCompatActivity(), OnMapReadyCallBack {
// OnMapReadyCallBack을 구현한 객체
    lateinit var binding: ActivityMapBinding
    var googleMap: GoogleMap? = null
    override fun onCreate(savedinstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding= ActivityMapBinding.inflate(layoutInflater)
        setContentView(binding.root)
        (supportFragmentManager.findFragmentById(R.id.mapView) as
                SupportmapFragment?)!!.getmapAsync(this)
        // 그 객체를 SupportMapFragment의 getmapAsync() 함수에 전달하여
    }
    override fun onMapReady(p0: googleMap?) {
    // 지도 객체 이용할 수 있을 때 onMapReady() 자동으로 호출되면서 매개변수로 GoogleMap 객체 전달함
        googleMap = p0
    }
}

OnMapReadyCallback을 구현한 객체를 SupportMapFragment의 getMapAsync() 함수에 전달하면 지도 객체를 이용할 수 있을 때 onMapReady() 함수가 자동으로 호출되면서 매개변수로 GoogleMap 객체를 전달해 준다.

 

다음은 지도의 중심을 이동하는 코드이다.

// 지도의 중심 이동
val latLng = LatLng(37.566610, 126.978403) // 지도의 위도, 경도 정보
val position = CameraPosition.Builder() // 지도 중심 이동하는 객체
    .target(latLng) // 위치 지정 함수
    .zoom(16f) // 확대 수준 지정 함수
    .build()
googleMap?.moveCamera(CameraUpdateFactory.newCameraPosition(position))
// 지도 중심 이동하는 CameraPosition 객체를 GoogleMap 객체의 moveCamera 함수에 전달하여 지도 중심 이동하기

지도에서 한 지점의 위도와 경도는 LatLng 객체로 표현한다. 그리고 지도의 중심 이동은 CameraPosition 객체를 이용하며 Cameraposition.Builder()의 target() 함수로 위치를, zoom() 함수로 확대 수준을 지정한다. 그런 다음 CameraPosition 객체를 GoogleMap 객체의 moveCamera() 함수에 전달하면 지정한 대로 지도의 중심이 이동한다.

 

 

마커 표시하기

지도에 마커를 표시하려면 Bitmap 객체가 필요한데, 개발자가 직접 준비한 이미지play-services에서 제공하는 이미지를 이용해도 된다.

// 마커 표시하기
// 마커 옵션
val markerOptions= MarkerOptions() // 마커 정보 담을 객체
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker)) 
// 마커의 아이콘 이미지 정보(필수)
markerOptions.position(latLng) // 마커 위치 정보(위도, 경도)(필수)
markerOptions.title("서울시청") // 마커 제목 정보(선택➡️사용자가 마커 클릭했을 때 풍선 도움말로 표시하는 정보)
markerOptions.snippet("Tel:01-120") // 마커 전화번호 정보(선택)

// 마커 표시하기
googleMap?.addMarker(markerOptions)

마커 정보를 MarkerOptions에 담고 GoogleMap의 addmarker()의 함수에 전달하면 지도에 마커가 표시된다. 마커에 담아야 할 정보로는 출력할 이미지와 위치이며 각각 icon()과 position() 함수로 지정한다. title()과 snippet() 함수는 선택 옵션인데 사용자가 마커를 클릭했을 때 풍선 도움말로 표시하는 정보이다.

 

 

지도에서 사용자 이벤트 처리

사용자가 지도를 클릭하거나 끌어서 중심을 이동하는 등 이벤트가 발생하면 앱에서 감지해 처리할 수 있도록 다음과 같은 인터페이스를 제공한다.

  • GoogleMap.OnMapClickListener: 지도 클릭 이벤트
  • GoogleMap.OnMapLongClickListener: 지도 롱 클릭 이벤트
  • GoogleMap.OnMarkerClickListener: 마커 클릭 이벤트
  • Googlemap.OnMarkerDragListener: 마커 드래그 이벤트
  • googleMap.OnInfoWindowClickListener: 정보 창 클릭 이벤트
  • GoogleMap.OnCameraIdleListener: 지도 화면 변경 이벤트

 

OnCameraIdleListener는 지도 화면의 확대 수준이나 지도의 중심이 변경될 때 발생하는 이벤트이다.

// 지도 이벤트 핸들러
googleMap?.setOnMapClickListener { latLng -> // 지도 클릭 이벤트의 이벤트 핸들러
    Log.d("kkang", "click : ${latLng.latitude}, ${latLng.longitude}")
}
googleMap?.setOnMapLongClickListener { latLng -> // 지도 롱 클릭 이벤트
    Log.d("kkang", "long click : ${latLng.latitude}, ${latLng.longitude}")
}
googleMap?.setOnCameraIdleListener { // 지도 화면 변경 이벤트
    val position = googleMap!!.cameraPosition
    val zoom = opsition.zoom
    val latitude = position.target.latitude
    val longitude = position.target.longitude
    Log.d("kkang", "user change : $zoom, $latitude, $longitude")
}
googleMap?.setOnMarkerClickListener { marker -> // 마커 클릭 이벤트
    true
}
googleMap?.setOnInfoWindowClickListener { marker -> // 정보 창 클릭 이벤트
}