매니페스트, xml, 종속성 추가 과정
https://developers.google.com/maps/documentation/android-sdk/config?hl=ko
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mapwithmarker">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<!--
The API key for Google Maps-based APIs.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
<activity
android:name=".MapsMarkerActivity"
android:label="@string/title_activity_maps"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.mapwithmarker.MapsMarkerActivity" />
dependencies 에 라이브러리 추가
implementation ("com.google.android.gms:play-services-maps:18.2.0")
implementation ("com.google.android.gms:play-services-location:21.1.0")
Activity의 onCreate() 메서드에서 레이아웃 파일을 콘텐츠 뷰로 설정합니다. FragmentManager.findFragmentById()를 호출하여 지도 프래그먼트의 핸들을 가져옵니다. 그런 다음 getMapAsync()를 사용하여 지도 콜백에 등록합니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Retrieve the content view that renders the map.
setContentView(R.layout.activity_maps)
// Get the SupportMapFragment and request notification when the map is ready to be used.
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
mapFragment?.getMapAsync(this)
}
OnMapReadyCallback 인터페이스를 구현하고, GoogleMap 객체를 사용할 수 있을 때 지도를 설정하도록 onMapReady() 메서드를 재정의합니다.
class MapsMarkerActivity : AppCompatActivity(), OnMapReadyCallback {
// ...
override fun onMapReady(googleMap: GoogleMap) {
val sydney = LatLng(-33.852, 151.211)
googleMap.addMarker(
MarkerOptions()
.position(sydney)
.title("Marker in Sydney")
)
}
}
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
/**
* 특정 위치를 나타내는 마커(핀)와 함께 Google 지도를 표시하는 활동입니다.
*/
class MapsMarkerActivity : AppCompatActivity(), OnMapReadyCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Retrieve the content view that renders the map.
setContentView(R.layout.activity_maps)
//SupportMapFragment를 가져오고 지도를 사용할 준비가 되면 알림을 요청합니다.
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
mapFragment?.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
val sydney = LatLng(-33.852, 151.211)
googleMap.addMarker(
MarkerOptions()
.position(sydney)
.title("Marker in Sydney")
)
googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}
}
GoogleMap.OnMapClickListener: 지도 클릭 이벤트
GoogleMap.OnMapLongClickListener: 지도 롱 클릭 이벤트
GoogleMap.OnMarkerClickListener: 마커 클릭 이벤트
GoogleMap.OnMarkerDragListener: 마커 드래그 이벤트
GoogleMap.OnInfoWindowClickListener: 정보 창 클릭 이벤트
GoogleMap.OnCameraIdleListener: 지도 화면 변경 이벤트
googleMap?.setOnMapClickListener { latLng ->
Log.d("map_test", "click : ${latLng.latitude} , ${latLng.longitude}")
}
googleMap?.setOnMapLongClickListener { latLng ->
Log.d("map_test", "long click : ${latLng.latitude} , ${latLng.longitude}")
}
googleMap?.setOnCameraIdleListener {
val position = googleMap!!.cameraPosition
val zoom = position.zoom
val latitude = position.target.latitude
val longitude = position.target.longitude
Log.d("map_test", "User change : $zoom $latitude , $longitude")
}
googleMap?.setOnMarkerClickListener { marker ->
true
}
googleMap?.setOnInfoWindowClickListener { marker ->
}
참고
https://developers.google.com/maps/documentation/android-sdk/map-with-marker?hl=ko#kotlin
마커가 포함된 지도 추가 | Android용 Maps SDK | Google for Developers
의견 보내기 마커가 포함된 지도 추가 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 튜토리얼에서는 Android 앱에 Google 지도를 추가하는 방법을 설명합니
developers.google.com
https://developers.google.com/maps/documentation/android-sdk/config?hl=ko
Android 스튜디오 프로젝트 설정 | Android용 Maps SDK | Google for Developers
의견 보내기 Android 스튜디오 프로젝트 설정 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 빠른 시작에 자세히 설명되어 있는 Google 지도
developers.google.com
간단한 예제
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import com.example.googlemap.databinding.ActivityMainBinding
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
private var _binding: ActivityMainBinding? = null
private val binding get() = _binding!!
lateinit var mGoogleMap: GoogleMap
lateinit var fusedLocationClient: FusedLocationProviderClient //위치 서비스
lateinit var locationCallback: LocationCallback //위치 정보 받기 위한 콜백
lateinit var locationPermission: ActivityResultLauncher<Array<String>> //퍼미션
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
locationPermission =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
if (result.all { it.value }) {
(supportFragmentManager.findFragmentById(R.id.mapView) as SupportMapFragment)!!.getMapAsync(
this
)//getMapAsync -> onMapReady
} else {//문제 발생시
Toast.makeText(this, "권한 승인이 필요합니다.", Toast.LENGTH_SHORT).show()
}
}
//권한 요청
locationPermission.launch(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
),
)
}
//지도 객체를 이용할 수 있는 상황이 될 때 /권한 허용된 상태라면 getMapAsync
override fun onMapReady(p0: GoogleMap) {
//onMapReady가 되면 마커 하나
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 //1초 마다 갱신
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.")
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 markerOptions = MarkerOptions().position(LATLNG).title("나 여기 있어용~")
val cameraPosition = CameraPosition.Builder().target(LATLNG).zoom(15.0f).build()
mGoogleMap.addMarker(markerOptions)
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
}
}