이 Codelab 정보
1. 시작하기 전에
Google 지도로 앱을 빌드하면 위성 이미지, 지도를 위한 강력한 UI 컨트롤, 위치 추적, 위치 마커와 같은 기능을 앱에 추가할 수 있습니다. 유명한 낚시 또는 등산 구역의 위치와 같이 자체 데이터 세트의 정보를 표시하여 표준 Google 지도에 가치를 더할 수 있습니다. 보물찾기나 증강 현실 게임과 같이 플레이어가 실제 세계를 탐험하는 게임을 만들 수도 있습니다.
이 강의에서는 맞춤설정된 지도와 사용자의 위치를 보여주는 Wander라는 Google 지도 앱을 만듭니다.
기본 요건
다음 지식:
- Android 스튜디오를 사용하여 기본 Android 앱을 만들고 실행하는 방법
- 문자열과 같은 리소스를 만들고 관리하는 방법
- Android 스튜디오를 사용하여 코드를 리팩터링하고 변수 이름을 바꾸는 방법
- 사용자가 Google 지도를 사용하는 방법
- 런타임 권한을 설정하는 방법
학습할 내용
- Google API 콘솔에서 API 키를 가져와 앱에 등록하는 방법
- 앱에 Google 지도를 통합하는 방법
- 다양한 지도 유형을 표시하는 방법
- Google 지도의 스타일을 지정하는 방법
- 지도에 마커를 추가하는 방법
- 사용자가 관심 장소에 마커를 배치할 수 있도록 하는 방법 (POI)
- 위치 추적을 사용 설정하는 방법
- Google 지도가 삽입된
Wander앱을 만드는 방법 - 마커 및 스타일 지정과 같은 앱의 맞춤 기능을 만드는 방법
- 앱에서 위치 추적을 사용 설정하는 방법
2. 앱 개요
이 Codelab에서는 맞춤 스타일을 지정하여 Google 지도를 표시하는 Wander 앱을 만듭니다. Wander 앱을 사용하면 위치에 마커를 놓거나 오버레이를 추가하거나 위치를 실시간으로 확인할 수 있습니다.

3. 작업: 프로젝트 설정 및 API 키 가져오기
Android용 Maps SDK를 사용하려면 API 키가 필요합니다. API 키를 가져오려면 프로젝트를 API 및 서비스 페이지를 참조하세요. API 키는 앱을 작성자와 연결하는 디지털 인증서에 연결됩니다. 디지털 인증서 사용 및 앱 서명에 관한 자세한 내용은 앱 서명을 참고하세요.
이 Codelab에서는 디버그 인증서에 API 키를 사용합니다. 디버그 인증서는 디버그 빌드 서명에 설명된 대로, 의도적으로 안전하지 않습니다. Android용 Maps SDK를 사용하는 게시된 Android 앱에는 두 번째 API 키, 즉 출시 인증서용 키가 필요합니다. 출시 인증서 가져오기에 대한 자세한 내용은 API 키 가져오기를 참고하세요.
Android 스튜디오에는 유용한 템플릿 코드를 생성하는 Google Maps Activity 템플릿이 포함되어 있습니다. 템플릿 코드에는 API 키 가져오기를 간소화하는 링크가 포함된 google_maps_api.xml 파일이 포함되어 있습니다.
1단계: 지도 템플릿으로 Wander 프로젝트 만들기
- 새 Android 스튜디오 프로젝트를 만듭니다.
- Google Maps Activity 템플릿을 선택합니다.

- 프로젝트 이름을
Wander로 지정합니다. - 최소 API 수준을 API 19로 설정합니다. 언어가 Kotlin인지 확인합니다.
- 마침을 클릭합니다.
- 앱 빌드가 완료되면 프로젝트와 Android 스튜디오에서 자동으로 생성되는 다음과 같은 지도 관련 파일을 살펴봅니다.
google_maps_api.xml: 이 구성 파일을 사용하여 API 키를 보관합니다. 이 템플릿은 디버그용과 릴리스용 하나씩, 이렇게 두 개의 google_maps_api.xml 파일을 생성합니다. 디버그 인증서의 API 키 파일은 src/debug/res/values에 있습니다. 출시 인증서의 API 키 파일은 src/release/res/values에 있습니다. 이 Codelab에서는 디버그 인증서만 사용합니다.
activity_maps.xml: 이 레이아웃 파일에는 전체 화면을 채우는 단일 프래그먼트가 포함되어 있습니다. SupportMapFragment 클래스는 Fragment 클래스의 서브클래스입니다. SupportMapFragment은 앱에 지도를 배치하는 가장 간단한 방법입니다. 필요한 수명 주기 요구사항을 자동으로 처리하기 위한 지도 뷰를 둘러싸는 래퍼입니다.
추가 name 속성과 함께 ViewGroup에서 <fragment> 태그를 사용하여 레이아웃 파일에 SupportMapFragment를 포함할 수 있습니다.
android:name="com.google.android.gms.maps.SupportMapFragment"
MapsActivity.java: MapsActivity.java 파일은 onCreate() 메서드의 SupportMapFragment를 인스턴스화하고 getMapAsync(): 지도 시스템과 뷰를 자동으로 초기화합니다. SupportMapFragment가 포함된 활동은 OnMapReadyCallback 인터페이스와 인터페이스의 onMapReady() 메서드를 구현해야 합니다. onMapReady() 메서드는 지도가 로드될 때 호출됩니다.
2단계: API 키 가져오기
- google_maps_api.xml 파일의 디버그 버전을 엽니다.
- 파일에서 긴 URL이 포함된 댓글을 찾습니다. URL의 매개변수에는 앱에 대한 특정 정보가 포함됩니다.
- URL을 복사하여 브라우저에 붙여넣습니다.
- 안내에 따라 API 및 서비스 페이지를 참조하세요. 제공된 URL의 매개변수로 인해 페이지는 Android용 Maps SDK를 자동으로 사용 설정합니다.
- API 키 만들기를 클릭합니다.
- 다음 페이지에서 API 키 섹션으로 이동하여 방금 만든 키를 클릭합니다.
- 키 제한을 클릭하고 Android용 Maps SDK를 선택하여 키 사용을 Android 앱으로 제한합니다.
- 생성된 API 키를 복사합니다. '
AIza"'(으)로 시작합니다. google_maps_api.xml파일에서YOUR_KEY_HERE라고 표시된google_maps_key문자열에 키를 붙여넣습니다.- 앱을 실행합니다. 호주 시드니에 설정된 마커가 포함된 삽입된 지도가 활동에 표시됩니다. 시드니 마커는 템플릿의 일부이며 나중에 변경할 수 있습니다.

3단계: mMap 이름 바꾸기
MapsActivity에는 GoogleMap 유형인 mMap라는 비공개 lateinit var가 있습니다. Kotlin 이름 지정 규칙을 따르려면 mMap의 이름을 map로 변경합니다.
MapsActivity에서mMap를 마우스 오른쪽 버튼으로 클릭하고 Refactor >를 클릭합니다. 이름 바꾸기...

- 변수 이름을
map로 변경합니다.
onMapReady() 함수에서 mMap에 대한 모든 참조도 map로 변경되는 것을 볼 수 있습니다.
4. 작업: 지도 유형 추가하기
Google 지도에는 일반, 하이브리드, 위성, 지형 및 '없음' 등 여러 지도 유형이 있습니다. (지도가 전혀 없을 때)
|
|
|
|
일반 맵 | 위성 지도 | 하이브리드 지도 | 지형 지도 |
각 지도 유형은 서로 다른 종류의 정보를 제공합니다. 예를 들어, 자동차에서 내비게이션을 위해 지도를 사용하는 경우 도로 이름을 확인하는 것이 유용하므로 일반 옵션을 사용할 수 있습니다. 하이킹을 할 때 지형 지도는 정상까지 올라가기 위해 얼마나 더 올라가야 하는지 파악하는 데 도움이 될 수 있습니다.
이 작업에서는 다음 작업을 수행합니다.
- 사용자가 지도 유형을 변경할 수 있는 옵션 메뉴가 있는 앱 바를 추가합니다.
- 지도의 시작 위치를 내 집 위치로 이동합니다.
- 지도에서 단일 위치를 나타내고 라벨을 포함할 수 있는 마커 지원을 추가합니다.
지도 유형 메뉴 추가
이 단계에서는 사용자가 지도 유형을 변경할 수 있는 옵션 메뉴가 있는 앱 바를 추가합니다.
- 새 메뉴 XML 파일을 만들려면 res 디렉터리를 마우스 오른쪽 버튼으로 클릭하고 New > Android 리소스 파일.
- 대화상자에서 파일 이름을
map_options로 지정합니다. - 리소스 유형으로 메뉴를 선택합니다.
- 확인을 클릭합니다.
- 코드 탭에서 새 파일의 코드를 다음 코드로 바꿔 지도 메뉴 옵션을 만듭니다. '없음' '없음'으로 인해 지도 유형이 생략되었습니다. 지도가 전혀 없을 수 있습니다. 이 단계에서 오류가 발생하지만 다음 단계에서 해결할 수 있습니다.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/normal_map"
android:title="@string/normal_map"
app:showAsAction="never" />
<item
android:id="@+id/hybrid_map"
android:title="@string/hybrid_map"
app:showAsAction="never" />
<item
android:id="@+id/satellite_map"
android:title="@string/satellite_map"
app:showAsAction="never" />
<item
android:id="@+id/terrain_map"
android:title="@string/terrain_map"
app:showAsAction="never" />
</menu>
strings.xml에서 오류를 해결하기 위해title속성의 리소스를 추가합니다.
<resources>
...
<string name="normal_map">Normal Map</string>
<string name="hybrid_map">Hybrid Map</string>
<string name="satellite_map">Satellite Map</string>
<string name="terrain_map">Terrain Map</string>
<string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
<string name="dropped_pin">Dropped Pin</string>
<string name="poi">poi</string>
</resources>
MapsActivity에서onCreateOptionsMenu()메서드를 재정의하고map_options리소스 파일에서 메뉴를 확장합니다.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.map_options, menu)
return true
}
MapsActivity.kt에서onOptionsItemSelected()메서드를 재정의합니다. 사용자의 선택이 반영되도록 지도 유형 상수를 사용하여 지도 유형을 변경합니다.
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
// Change the map type based on the user's selection.
R.id.normal_map -> {
map.mapType = GoogleMap.MAP_TYPE_NORMAL
true
}
R.id.hybrid_map -> {
map.mapType = GoogleMap.MAP_TYPE_HYBRID
true
}
R.id.satellite_map -> {
map.mapType = GoogleMap.MAP_TYPE_SATELLITE
true
}
R.id.terrain_map -> {
map.mapType = GoogleMap.MAP_TYPE_TERRAIN
true
}
else -> super.onOptionsItemSelected(item)
}
- 앱을 실행합니다.
- 지도 유형을 변경하려면
아이콘을 클릭합니다. 모드별로 지도 모양이 어떻게 변하는지 확인하세요.

5. 작업: 마커 추가하기
기본적으로 onMapReady() 콜백에는 Google 지도가 만들어진 오스트레일리아 시드니에 마커를 배치하는 코드가 포함됩니다. 또한 기본 콜백은 지도를 시드니로 이동하도록 애니메이션을 적용합니다.
이 작업에서는 지도의 카메라를 집으로 이동하고 지정한 수준으로 확대/축소한 후 마커를 배치합니다.
1단계: 집을 확대/축소하고 마커 추가하기
MapsActivity.kt파일에서onMapReady()메서드를 찾습니다. 시드니에 마커를 배치하고 카메라를 이동하는 코드를 삭제합니다. 이제 메서드는 다음과 같이 표시됩니다.
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
}
- 이 안내에 따라 집의 위도와 경도를 확인하세요.
- 위도 값과 경도 값을 생성하고 부동 소수점 값을 입력합니다.
val latitude = 37.422160
val longitude = -122.084270
homeLatLng라는 새LatLng객체를 만듭니다.homeLatLng객체에서 방금 만든 값을 전달합니다.
val homeLatLng = LatLng(latitude, longitude)
- 지도에서 얼마나 확대하고 싶은지에 관한
val를 만듭니다. 확대/축소 수준 15f를 사용합니다.
val zoomLevel = 15f
확대/축소 수준은 지도에서 얼마나 확대된 정도를 제어합니다. 다음 목록을 통해 각 확대/축소 수준에서 표시되는 세부정보 수준을 알 수 있습니다.
1: 전 세계5: 대륙10: 도시15: 도로20: 건물
map객체에서moveCamera()함수를 호출하여 카메라를homeLatLng로 이동하고CameraUpdateFactory.newLatLngZoom()를 사용하여CameraUpdate객체를 전달합니다.homeLatLng객체와zoomLevel를 전달합니다.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
homeLatLng의 지도에 마커를 추가합니다.
map.addMarker(MarkerOptions().position(homeLatLng))
최종 메서드는 다음과 같습니다.
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
//These coordinates represent the latitude and longitude of the Googleplex.
val latitude = 37.422160
val longitude = -122.084270
val zoomLevel = 15f
val homeLatLng = LatLng(latitude, longitude)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
map.addMarker(MarkerOptions().position(homeLatLng))
}
- 앱을 실행합니다. 지도가 집으로 이동하고, 원하는 수준으로 확대/축소하고, 집에 마커를 배치합니다.

2단계: 사용자가 긴 클릭으로 마커를 추가할 수 있도록 허용하기
이 단계에서는 사용자가 지도에서 위치를 길게 터치할 때 마커를 추가합니다.
MapsActivity에GoogleMap를 인수로 사용하는setMapLongClick()라는 메서드 스텁을 만듭니다.- 지도 객체에
setOnMapLongClickListener리스너를 연결합니다.
private fun setMapLongClick(map:GoogleMap) {
map.setOnMapLongClickListener { }
}
setOnMapLongClickListener()에서addMarker()메서드를 호출합니다. 전달된LatLng로 설정된 위치를 사용하여 새MarkerOptions객체를 전달합니다.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
map.addMarker(
MarkerOptions()
.position(latLng)
)
}
}
onMapReady()메서드 끝에서map를 사용하여setMapLongClick()를 호출합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapLongClick(map)
}
- 앱을 실행합니다.
- 지도를 길게 터치하여 원하는 위치에 마커를 배치합니다.
- 마커를 탭하면 화면 중앙에 배치됩니다.

3단계: 마커에 대한 정보 창 추가
이 단계에서는 마커를 탭할 때 마커의 좌표를 표시하는 InfoWindow를 추가합니다.
setMapLongClick()setOnMapLongClickListener()에서snippet의val를 만듭니다. 스니펫은 제목 뒤에 표시되는 추가 텍스트입니다. 스니펫은 마커의 위도와 경도를 표시합니다.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
// A snippet is additional text that's displayed after the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
)
}
}
addMarker()에서R.string.dropped_pin문자열 리소스를 사용하여 마커의title를 고정된 핀으로 설정합니다.- 마커의
snippet를snippet로 설정합니다.
완성된 함수는 다음과 같습니다.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
// A Snippet is Additional text that's displayed below the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
.title(getString(R.string.dropped_pin))
.snippet(snippet)
)
}
}
- 앱을 실행합니다.
- 위치 마커를 배치하려면 지도를 길게 터치합니다.
- 마커를 탭하여 정보 창을 표시합니다.

4단계: 관심 장소 리스너 추가
기본적으로 관심 장소 (POI)는 해당 아이콘과 함께 지도에 표시됩니다. 관심 장소에는 공원, 학교, 정부 건물 등이 포함됩니다. 지도 유형을 normal로 설정하면 비즈니스 관심 장소도 지도에 표시됩니다. 비즈니스 관심 장소는 상점, 음식점, 호텔 등의 비즈니스를 나타냅니다.
이 단계에서는 GoogleMap.OnPoiClickListener를 지도에 추가합니다. 이 클릭 리스너는 사용자가 관심 장소를 클릭하는 즉시 지도에 마커를 배치합니다. 클릭 리스너는 관심 장소 이름이 포함된 정보 창도 표시합니다.
MapsActivity에GoogleMap를 인수로 사용하는setPoiClick()라는 메서드 스텁을 만듭니다.setPoiClick()메서드에서 전달된GoogleMap에OnPoiClickListener를 설정합니다.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
}
}
setOnPoiClickListener()에서 마커의val poiMarker를 만듭니다 .MarkerOptions와 함께map.addMarker()를 사용하여 마커에 설정하고title을 관심 장소의 이름으로 설정합니다.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
}
}
setOnPoiClickListener()함수에서poiMarker의showInfoWindow()를 호출하여 정보 창을 즉시 표시합니다.
poiMarker.showInfoWindow()
setPoiClick() 함수의 최종 코드는 다음과 같습니다.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
poiMarker.showInfoWindow()
}
}
onMapReady()끝에서setPoiClick()를 호출하고map를 전달합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
setPoiClick(map)
}
- 앱을 실행하고 공원이나 커피숍과 같은 관심 장소를 찾습니다.
- 관심 장소를 탭하여 마커를 배치하고 정보 창에 관심 장소의 이름을 표시합니다.

6. 작업: 지도 스타일 지정
다양한 방법으로 Google 지도를 맞춤설정하여 나만의 지도를 만들 수 있습니다.
다른 프래그먼트를 맞춤설정하는 것처럼 사용 가능한 XML 속성을 사용하여 MapFragment 객체를 맞춤설정할 수 있습니다. 그러나 이 단계에서는 GoogleMap 객체의 메서드를 사용하여 MapFragment 콘텐츠의 디자인과 분위기를 맞춤설정합니다.
지도에 맞춤설정된 스타일을 만들려면 지도의 지형지물이 표시되는 방식을 지정하는 JSON 파일을 생성합니다. 이 JSON 파일을 수동으로 만들 필요가 없습니다. Google에서는 지도의 스타일을 시각적으로 지정한 후 JSON을 생성해 주는 지도 플랫폼 스타일 지정 마법사를 제공합니다. 이 작업에서는 레트로 테마로 지도의 스타일을 지정합니다. 즉, 지도는 빈티지 색상을 사용하고 색상이 지정된 도로를 추가합니다.
1단계: 지도의 스타일 만들기
- 브라우저에서 https://mapstyle.withgoogle.com/으로 이동합니다.
- 스타일 만들기를 선택합니다.
- Retro를 선택합니다.

- 옵션 더보기를 클릭합니다.

- 도로를 선택합니다. 채우기.
- 도로의 색상을 원하는 색상 (예: 분홍색)으로 변경합니다.

- 마침을 클릭합니다.

- 결과 대화상자에서 JSON 코드를 복사하고 원하는 경우 다음 단계에서 사용할 수 있도록 일반 텍스트 메모에 보관합니다.

2단계: 지도에 스타일 추가
- Android 스튜디오의
res디렉터리에서 리소스 디렉터리를 만들고 이름을raw로 지정합니다. JSON 코드와 같은raw디렉터리 리소스를 사용합니다. res/raw에map_style.json라는 파일을 만듭니다.- 저장된 JSON 코드를 새 리소스 파일에 붙여넣습니다.
MapsActivity에서onCreate()메서드 위에TAG클래스 변수를 만듭니다. 로깅 목적으로 사용됩니다.
private val TAG = MapsActivity::class.java.simpleName
- 또한
MapsActivity에서GoogleMap를 사용하는setMapStyle()함수를 만듭니다. setMapStyle()에서try{}블록을 추가합니다.try{}블록에서 성공적인 스타일 지정을 위한val success를 만듭니다. 다음 catch 블록을 추가합니다.try{}블록에서 JSON 스타일을 지도에 설정하고GoogleMap객체에서setMapStyle()를 호출합니다. JSON 파일을 로드하는MapStyleOptions객체를 전달합니다.- 결과를
success에 할당합니다.setMapStyle()메서드는 스타일 지정 파일을 파싱하고 스타일 설정의 성공 상태를 나타내는 불리언을 반환합니다.
private fun setMapStyle(map: GoogleMap) {
try {
// Customize the styling of the base map using a JSON object defined
// in a raw resource file.
val success = map.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
this,
R.raw.map_style
)
)
}
}
- false인
success의 if 문을 추가합니다. 스타일 지정에 실패하면 파싱에 실패한 로그를 출력합니다.
private fun setMapStyle(map: GoogleMap) {
try {
...
if (!success) {
Log.e(TAG, "Style parsing failed.")
}
}
}
catch{}블록을 추가하여 스타일 파일이 누락된 상황을 처리합니다.catch블록에서 파일을 로드할 수 없는 경우Resources.NotFoundException이 발생합니다.
private fun setMapStyle(map: GoogleMap) {
try {
...
} catch (e: Resources.NotFoundException) {
Log.e(TAG, "Can't find style. Error: ", e)
}
}
완성된 메서드는 다음 코드 스니펫과 같습니다.
private fun setMapStyle(map: GoogleMap) {
try {
// Customize the styling of the base map using a JSON object defined
// in a raw resource file.
val success = map.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
this,
R.raw.map_style
)
)
if (!success) {
Log.e(TAG, "Style parsing failed.")
}
} catch (e: Resources.NotFoundException) {
Log.e(TAG, "Can't find style. Error: ", e)
}
}
- 마지막으로
GoogleMap객체를 전달하는onMapReady()메서드에서setMapStyle()메서드를 호출합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapStyle(map)
}
- 앱을 실행합니다.
- 지도를
normal모드로 설정하면 새로운 스타일이 레트로 테마 설정과 선택한 색상의 도로로 표시됩니다.

3단계: 마커 스타일 지정
지도 마커의 스타일을 지정하여 지도를 더욱 맞춤설정할 수 있습니다. 이 단계에서는 기본 빨간색 마커를 더 멋진 것으로 변경합니다.
onMapLongClick()메서드에서 생성자의MarkerOptions()에 다음 코드 줄을 추가하여 기본 마커를 사용하지만 색상은 파란색으로 변경합니다.
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
이제 onMapLongClickListener()는 다음과 같이 표시됩니다.
map.setOnMapLongClickListener { latLng ->
// A snippet is additional text that's displayed after the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
.title(getString(R.string.dropped_pin))
.snippet(snippet)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
)
}
- 앱을 실행합니다. 이제 길게 클릭하면 나타나는 마커가 파란색 음영으로 표시됩니다.
onPoiClick()메서드에 스타일을 추가하지 않았으므로 관심 장소 마커는 여전히 빨간색입니다.

7. 작업: 오버레이 추가
Google 지도를 맞춤설정하는 한 가지 방법은 지도 위에 그림을 그리는 것입니다. 이 기술은 인기 있는 낚시터와 같이 특정 유형의 위치를 강조표시하려는 경우에 유용합니다.
- 도형: 지도에 다중선, 다각형, 원을 추가할 수 있습니다.
GroundOverlay객체: 지면 오버레이는 지도에 고정된 이미지입니다. 마커와 달리 지면 오버레이는 화면이 아닌 지표면을 향합니다. 지도를 회전하거나 기울이거나 확대/축소하면 이미지의 방향이 바뀝니다. 지면 오버레이는 단일 이미지를 지도의 한 영역에 고정하려는 경우에 유용합니다.
단계: 지면 오버레이 추가
이 작업에서는 Android 모양의 지면 오버레이를 홈 위치에 추가합니다.
- 이 Android 이미지를 다운로드하여
res/drawable폴더에 저장합니다. 파일 이름이android.png이어야 합니다.

onMapReady()에서 카메라를 홈 위치로 이동하도록 호출한 후GroundOverlayOptions객체를 만듭니다.- 객체를
androidOverlay라는 변수에 할당합니다.
val androidOverlay = GroundOverlayOptions()
BitmapDescriptorFactory.fromResource()메서드를 사용하여 다운로드한 이미지 리소스에서BitmapDescriptor객체를 만듭니다.- 결과
BitmapDescriptor객체를GroundOverlayOptions객체의image()메서드에 전달합니다.
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
- 원하는 오버레이의 너비(미터 단위)에 관한
float overlaySize를 만듭니다. 이 예에서는100f너비가 적합합니다.
position() 메서드를 호출하여 GroundOverlayOptions 객체의 position 속성을 설정하고 homeLatLng 객체와 overlaySize를 전달합니다.
val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
.position(homeLatLng, overlaySize)
GoogleMap객체에서addGroundOverlay()를 호출하고GroundOverlayOptions객체를 전달합니다.
map.addGroundOverlay(androidOverlay)
- 앱을 실행합니다.
- Android 이미지를 오버레이로 보려면
zoomLevel값을 18f로 변경합니다.

8. 작업: 위치 추적 사용 설정
사용자는 종종 Google 지도를 사용하여 현재 위치를 확인합니다. 지도에 기기 위치를 표시하려면 위치 데이터 레이어를 사용하면 됩니다.
위치 데이터 레이어는 지도에 내 위치 아이콘을 추가합니다.

사용자가 버튼을 탭하면 기기의 위치가 지도 중앙에 배치됩니다. 기기가 움직이지 않으면 위치는 파란색 점으로, 기기가 움직이는 경우 파란색 V자형으로 표시됩니다.
이 작업에서는 위치 데이터 레이어를 사용 설정합니다.
단계: 위치 정보 액세스 권한 요청
Google 지도에서 위치 추적을 사용하려면 한 줄의 코드가 필요합니다. 그러나 런타임 권한 모델을 사용하여 사용자가 위치 정보 액세스 권한을 부여했는지 확인해야 합니다.
이 단계에서는 위치 정보 액세스 권한을 요청하고 위치 추적을 사용 설정합니다.
AndroidManifest.xml파일에FINE_LOCATION권한이 이미 있는지 확인합니다. Google 지도 템플릿을 선택할 때 Android 스튜디오가 이 권한을 삽입했습니다.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
MapsActivity에서REQUEST_LOCATION_PERMISSION클래스 변수를 만듭니다.
private val REQUEST_LOCATION_PERMISSION = 1
- 권한이 부여되었는지 확인하려면
MapsActivity에서isPermissionGranted()라는 메서드를 만듭니다. 이 메서드에서 사용자가 권한을 부여했는지 확인합니다.
private fun isPermissionGranted() : Boolean {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
- 앱에서 위치 추적을 사용 설정하려면
MapsActivity에서 인수를 사용하지 않고 아무것도 반환하지 않는enableMyLocation()라는 메서드를 만듭니다. 내부에서ACCESS_FINE_LOCATION권한을 확인합니다. 권한이 부여되면 위치 레이어를 사용 설정합니다. 권한이 없다면 권한을 요청합니다.
private fun enableMyLocation() {
if (isPermissionGranted()) {
map.isMyLocationEnabled = true
}
else {
ActivityCompat.requestPermissions(
this,
arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
}
onMapReady()콜백에서enableMyLocation()를 호출하여 위치 레이어를 사용 설정합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
enableMyLocation()
}
onRequestPermissionsResult()메서드를 재정의합니다.requestCode가REQUEST_LOCATION_PERMISSION와 같은지 확인합니다. 설정된 경우 권한이 부여되었음을 의미합니다. 권한이 부여되면grantResults배열의 첫 번째 슬롯에PackageManager.PERMISSION_GRANTED가 포함되어 있는지도 확인합니다. true이면enableMyLocation()를 호출합니다.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray) {
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
enableMyLocation()
}
}
}
- 앱을 실행합니다. 기기 위치에 대한 액세스를 요청하는 대화상자가 있어야 합니다. 권한을 허용하세요.

이제 지도에 기기의 현재 위치가 파란색 점으로 표시됩니다. 위치 버튼이 있습니다. 지도를 내 위치에서 멀리 이동한 다음 이 버튼을 클릭하면 기기의 위치가 지도의 중심에 다시 맞춰집니다.

9. 솔루션 코드
완료된 Codelab의 코드를 다운로드합니다.
$ git clone https://github.com/googlecodelabs/android-kotlin-geo-maps
또는 ZIP 파일로 저장소를 다운로드한 다음 압축을 풀고 Android 스튜디오에서 열어도 됩니다.
10. 요약
축하합니다. Android Kotlin 앱에 Google 지도를 추가하고 스타일을 지정했습니다.
12. 다음 Codelab
이 과정의 다른 Codelab 링크는 Kotlin 기반 Android 고급 Codelab 방문 페이지를 참고하세요.



