Design-loving front-end engineer
Ryong
Design-loving front-end engineer
전체 방문자
오늘
어제
    • Framework
    • React
      • Concept
      • Library
      • Hook
      • Component
      • Test
    • NodeJS
    • Android
      • Concept
      • Code
      • Sunflower
      • Etc
    • Flutter
      • Concept
      • Package
    • Web
    • Web
    • CSS
    • Language
    • JavaScript
    • TypeScript
    • Kotlin
    • Dart
    • Algorithm
    • Data Structure
    • Programmers
    • Management
    • Git
    • Editor
    • VSCode
    • Knowledge
    • Voice
Design-loving front-end engineer

Ryong

[Android] [Kotlin] Google Map
Android/Code

[Android] [Kotlin] Google Map

2021. 9. 24. 16:57

Google Map 기초

사전 작업

구글 플레이 서비스 SDK 설치하기

◽  Google Play services를 설치해준다.

 

Google Maps Activity로 시작하기

 

Google Map API 키 받기

✔  Google Map 액티비티로 프로젝트를 생성하면 google_maps_api.xml이 자동을 생성되는데 해당 파일에서 구글 맵을 사용하기 위한 API 키를 받을 수 있는 링크를 만들어준다.

✔  별도로 접근하기 위해서는 Google Cloud Platform에서 프로젝트를 생성하고, 해당 프로젝트의 SHA-1 키를 등록한 후, 키를 받아야 한다.

 

코드 분석

build.gradle

implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'

 

AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--    정확한 위치 확보(네트워크 위치 + GPS 위치)-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--    도시 블록 내에서의 정확한 위치(네트워크 위치)-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
 
    <application
        
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />
 
        <activity
            android:name=".MapsActivity"
            android:label="@string/title_activity_maps">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
cs

 

activity_maps.xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    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=".MapsActivity" />
 
cs

◽  Google Maps API는 SupportMapFragment에 구글 지도를 표시한다.

 

BaseActivity.kt

✔  Permission 관련 코드들은 BaseActivity로 분리하여 설계

더보기
abstract class BaseActivity : AppCompatActivity() {

    abstract fun permissionGranted(requestCode: Int)
    abstract fun permissionDenied(requestCode: Int)

    fun requirePermissions(permissions: Array<String>, requestCode: Int) {
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            permissionGranted(requestCode)
        } else {
            val isAllPermissionsGranted = permissions.all { 
                checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED }
            if (isAllPermissionsGranted) {
                permissionGranted(requestCode)
            } else {
                ActivityCompat.requestPermissions(this, permissions, requestCode)
            }
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
            permissionGranted(requestCode)
        } else {
            permissionDenied(requestCode)
        }
    }
}

 

MapsActivity.kt

class MapsActivity : BaseActivity(), OnMapReadyCallback {

    val binding by lazy { ActivityMapsBinding.inflate(layoutInflater) }

    private lateinit var mMap: GoogleMap
    private lateinit var discriptor: BitmapDescriptor
    private lateinit var fusedLocationClient: FusedLocationProviderClient  // 위칫값 사용하기 위해
    private lateinit var locationCallback: LocationCallback  // 위칫값 요청에 대한 갱신 정보를 받기 위해

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        val permissions = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION)

        requirePermissions(permissions, 999)
    }

    override fun permissionGranted(requestCode: Int) {
        startProcess()
    }

    override fun permissionDenied(requestCode: Int) {
        Toast.makeText(this
            , "권한 승인이 필요합니다."
            , Toast.LENGTH_LONG)
            .show()
    }
}
fun startProcess() {
    val mapFragment = supportFragmentManager
        .findFragmentById(R.id.map) as SupportMapFragment
    mapFragment.getMapAsync(this)  // 구글 지도를 그려달라는 요청
}

override fun onMapReady(googleMap: GoogleMap) {  // onMapReadyCallback 메서드 오버라이드
    mMap = googleMap  // 액티비티 전체에서 맵을 사용할 수 있도록

    // 현재 위치를 검색하기 위해서 FusedLocationProviderClient 사용
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    updateLocation()

    /* 마커 아이콘 설정 */
    var bitmapDrawable: BitmapDrawable
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        bitmapDrawable = getDrawable(R.drawable.icon_here) as BitmapDrawable
    } else {
        bitmapDrawable = resources.getDrawable(R.drawable.icon_here) as BitmapDrawable
    }
    discriptor = BitmapDescriptorFactory.fromBitmap(bitmapDrawable.bitmap)
}

@SuppressLint("MissingPermission")
fun updateLocation() {
    /* 위치 정보를 요청할 locationRequest 생성하고 정확도와 주기를 설정 */
    val locationRequest = LocationRequest.create()  
    locationRequest.run {
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        interval = 1000
    }

    locationCallback = object : LocationCallback() {  // 해당 주기마다 반환받을 locationCallback
        override fun onLocationResult(locationResult: LocationResult?) {
            locationResult?.let {
                for(location in it.locations) {
                    Log.d("Location", "${location.latitude} , ${location.longitude}")
                    setLastLocation(location)
                }
            }
        }
    }
    
    fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
    
}

◽  fusedLocationClient.requestLocationUpdates 코드는 권한 처리가 필요한데, 현재 코드에서는 확인할 수 없기 때문에 메서드 상단에 해당 코드에 대한 권한은 체크하지 않아도 된다는 의미로 @SuppressLint("MissingPermission")를 붙여준다.

◽  해당 코드의 마지막 requestLocationUpdates을 실행하면 이제 1초마다 한 번씩 변화된 위치 정보가 LocationCallback의 onLocationResult()로 전달된다.

◽  onLocationResult()는 반환받은 정보에서 위치 정보를 setLastLocation()으로 전달한다.

 

fun setLastLocation(lastLocation: Location) {
    val LATLNG = LatLng(lastLocation.latitude, lastLocation.longitude)  // 전달받은 위치를 좌표로 마커를 생성

    /* 마커 추가 및 옵션 */
    val markerOptions = MarkerOptions()  // 마커 추가
        .position(LATLNG)  // 마커의 좌표
        .title("Here!")  // 마커의 제목
        .icon(discriptor)
    // .snippet("정보창 추가")

    /* 카메라 위치를 현재 위치로 세팅하고 마커와 함께 지도에 반영 */
    val cameraPosition = CameraPosition.Builder()
        .target(LATLNG)  // 카메라의 목표 지점
        .zoom(15.0f)  // 카메라 줌
       .build()
    // bearing : 지도의 수직선이 북쪽을 기준으로 시계 방향 단위로 측정되는 방향
    // tilt : 카메라의 기울기

    mMap.clear()  // 마커를 지도에 반영하기 전에 clear를 사용해서 이전에 그려진 마커가 있으면 지운다.
    mMap.addMarker(markerOptions)  // 지도에 마커를 추가
    mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
    // CameraUpdateFactory.newCameraPosition(cameraPosition) : 카메라 포지션에 지도에서 사용할 수 있는 카메라 정보가 생성된다.
    // mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) : 카메라 포지션을 기준으로 지도의 위치, 배율, 기울기 등이 변경돼서 표시된다.
}

 

저작자표시

'Android > Code' 카테고리의 다른 글

[Android] [Kotlin] 객체 인스턴스  (0) 2021.11.05
[Project] [Android] [Kotlin] Log Window  (0) 2021.10.18
[Android] [Kotlin] EditText 자동 포커싱 및 키보드  (0) 2021.09.23
[Android] [Kotlin] Dialog로 액티비티 띄우기  (0) 2021.09.15
[Android] [Kotlin] chooser Intent (카메라, 갤러리)  (0) 2021.09.12
    'Android/Code' 카테고리의 다른 글
    • [Android] [Kotlin] 객체 인스턴스
    • [Project] [Android] [Kotlin] Log Window
    • [Android] [Kotlin] EditText 자동 포커싱 및 키보드
    • [Android] [Kotlin] Dialog로 액티비티 띄우기
    Design-loving front-end engineer
    Design-loving front-end engineer
    디자인에 관심이 많은 모바일 앱 엔지니어 Ryong입니다.

    티스토리툴바