1. 시작하기 전에
이 Codelab에서는 Google Maps Platform Navigation SDK를 사용하여 사전 구성된 대상 위치로 이동하는 간단한 Android 앱을 만드는 방법을 알아봅니다.
완료되면 앱은 다음과 같이 표시됩니다.
기본 요건
- Kotlin을 이용한 기본 Android 앱 개발에 관한 지식
- 지도, 위치, 좌표와 같은 기본적인 Google Maps SDK 개념에 관한 어느 정도의 지식
학습할 내용
- Navigation SDK를 사용하여 대상으로 이동하는 간단한 Android 앱을 만드는 방법
- 원격 Google Maven 저장소에서 Navigation SDK를 통합하는 방법
- Navigation SDK 최종 사용자 약관에 따른 위치 정보 액세스 권한 및 사용자 계약 관리 방법
- SDK를 초기화하는 방법
- 목적지를 설정하고 내비게이션 안내를 시작하는 방법
필요한 항목
- Android 스튜디오의 최신 안정화 버전이 설치된 컴퓨터 이 Codelab은 Android 스튜디오 Jellyfish를 사용하여 작성되었습니다. 다른 버전을 사용하는 경우 인터페이스와 구성요소의 모양과 레이아웃이 다를 수 있습니다.
- 결제가 사용 설정된 Google 계정 및 프로젝트
- USB 디버깅이 사용 설정된 개발자 모드의 Android 기기 또는 Android 에뮬레이터 어떤 옵션을 선택하든 Navigation SDK의 최소 요구사항을 충족해야 합니다.
2. 설정
Google Cloud Platform 계정과 결제가 사용 설정된 프로젝트가 없는 경우 Google Maps Platform 시작하기 안내(https://developers.google.com/maps/gmp-get-started)에 따라 Google Cloud 프로젝트를 설정합니다.
콘솔에서 Google Cloud 프로젝트를 선택합니다.
Cloud Console에서 프로젝트 드롭다운 메뉴를 클릭하고 이 Codelab에 사용할 프로젝트를 선택합니다.
프로젝트에서 Navigation SDK 사용 설정
Google Cloud Marketplace에서 이 Codelab에 필요한 Google Maps Platform API 및 SDK를 사용 설정합니다.
API로 이동 및 서비스 > 라이브러리를 열고 'Navigation SDK'를 검색합니다.
검색 결과 1개가 표시됩니다.
Navigation SDK 결과를 클릭하여 제품 세부정보 페이지를 엽니다. 사용 설정 버튼을 클릭하여 프로젝트에서 SDK를 사용 설정합니다.
Android용 Google Maps SDK에도 이 프로세스를 반복합니다.
API 키 만들기
Cloud Console의 사용자 인증 정보 페이지에서 API 키를 생성합니다. Google Maps Platform 시작하기의 빠른 시작 섹션 3단계에 나온 단계를 따르세요. Google Maps Platform에 대한 모든 요청에는 API 키가 필요합니다.
3. 샘플 프로젝트 파일 가져오기
이 섹션에서는 이 Codelab의 GitHub 저장소에서 파일을 클론하여 기본 빈 Android 스튜디오 프로젝트를 설정하는 방법을 설명합니다. GitHub 저장소에는 Codelab 코드의 이전 버전과 이후 버전이 포함되어 있습니다. 이 Codelab은 빈 프로젝트 템플릿으로 시작하고 완성된 상태로 빌드됩니다. 문제가 발생하면 저장소의 완료된 프로젝트를 참고로 사용할 수 있습니다.
이 GitHub 저장소를 클론하여 이 Codelab의 코드를 가져옵니다.
git clone https://github.com/googlemaps-samples/codelab-navigation-101-android-kotlin.git
git이 설치되어 있지 않으면 다음 버튼을 클릭하여 코드를 가져옵니다.
최대한 빨리 시작할 수 있도록 이 Codelab을 따라 하는 데 도움이 되는 시작 코드가 저장소의 Starter
폴더에 포함되어 있습니다. 시작 프로젝트는 기본 앱 UI와 빌드 구성을 제공하지만 Navigation SDK는 추가되어 있지 않습니다. 언제든지 진행 상황을 확인하거나 건너뛰려는 경우 완료된 Solution
프로젝트도 있습니다.
Android 스튜디오에서 클론된 저장소 열기
저장소를 로컬에서 클론한 후에는 Android 스튜디오를 사용하여 Starter
폴더를 기존 프로젝트로 엽니다.
- 'Welcome to Android Studio' 대화상자에서 Open 버튼을 클릭합니다.
- 클론된 저장소를 저장한 폴더로 이동하여 최상위 '
codelab-navigation-101-android-kotlin
' 폴더 내의Starter
폴더를 선택합니다. - 프로젝트가 빌드되고 실행되는지 확인합니다.
가상 기기 추가 또는 하드웨어 기기 연결하기
Android 기기를 컴퓨터에 연결하려면 하드웨어 기기에서 앱을 실행하는 방법에 관한 Android 스튜디오의 안내를 따르세요. 또는 Android Virtual Device(AVD) Manager를 사용하여 가상 기기를 구성할 수 있습니다. 에뮬레이터를 선택할 때 Google API가 포함된 이미지를 선택해야 합니다.
Android 스튜디오에서 Run(실행) 메뉴 옵션 또는 재생 버튼 아이콘을 클릭합니다. 표시되는 메시지에 따라 기기를 선택합니다.
4. 앱에 Navigation SDK 추가
프로젝트에 Navigation SDK 라이브러리 및 API 키 추가
앱에 Navigation SDK 라이브러리를 추가하려면 앱 수준 build.gradle.kts
을 수정하여 Google Maven 저장소에서 Navigation SDK를 가져오고 버전 번호를 구성해야 합니다.
빌드 구성에서 Navigation SDK 버전 번호를 저장할 변수를 만듭니다.
나중에 쉽게 최신 버전으로 변경할 수 있도록 앱에서 사용되는 Navigation SDK 버전의 값을 포함하도록 앱 수준 build.gradle.kts
에서 변수를 설정합니다.
Navigation SDK 출시 노트에서 최신 버전 번호를 확인하세요.
val navSdkVersion by extra("6.0.0")
File > Project Structure > Variables에 있는 대화상자를 사용하여 이 변수와 다른 변수의 값을 수정할 수도 있습니다.
빌드 구성에 종속 항목 추가
이제 앱 수준 build.gradle.kts.
의 종속 항목 블록에 다음 API 종속 항목을 추가합니다. 사용되는 버전은 앱 수준 build.gradle.kts
에서 방금 설정한 ${navSdkVersion}
값입니다.
dependencies {
// Include the Google Navigation SDK.
api("com.google.android.libraries.navigation:navigation:${navSdkVersion}")
...
API 키 추가하기
Secrets Gradle 플러그인을 사용하여 API 키 관리
Secrets Gradle 플러그인을 사용하여 앱에서 API 키를 안전하게 관리하는 것이 좋습니다. 이 플러그인은 최상위 build.gradle.kts
파일의 종속 항목으로 초기 프로젝트 템플릿에 추가되었습니다.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") version "2.0.1" apply false
//... other plugin definitions here
}
최상위 디렉터리에서 secrets.properties
파일을 연 다음 YOUR_API_KEY
를 API 키로 바꿉니다. secrets.properties
가 버전 제어 시스템에 체크인되는 데서 제외되었으므로 키를 이 파일에 저장합니다.
MAPS_API_KEY=YOUR_API_KEY
이 주제에 관한 자세한 내용은 Navigation SDK 문서의 앱에 API 키 추가를 참고하세요.
local.defaults.properties의 콘텐츠 확인
빈 프로젝트에는 secrets.properties
파일과 동일한 폴더인 최상위 디렉터리에 local.defaults.properties
파일도 포함되어 있습니다. 파일을 열고 다음 코드를 살펴봅니다.
MAPS_API_KEY=DEFAULT_API_KEY
secrets.properties
가 프로젝트에 추가되지 않는 경우 MAPS_API_KEY
속성의 백업 값을 제공하기 위해 존재하므로 빌드가 실패하지 않습니다. 이 파일을 수정할 필요가 없습니다. MAPS_API_KEY
의 secrets.properties
정의를 찾을 수 없는 경우 기본값은 API 키 오류와 함께 런타임 시 실행 중인 앱을 중지합니다.
Android 매니페스트가 지정한 API 키를 사용하고 있는지 확인
app/src/main/AndroidManifest.xml을 엽니다. MAPS_API_KEY
속성은 애플리케이션의 API 키를 설정하는 데 사용됩니다.
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
앱 수준 build.gradle.kts
파일을 열고 secrets
속성을 찾습니다.
플러그인의 propertiesFileName
설정은 secrets.properties
로 설정되어야 하며 defaultPropertiesFileName
은 local.defaults.properties
를 읽어야 합니다.
secrets {
// Optionally specify a different file name containing your secrets.
// The plugin defaults to "local.properties"
propertiesFileName = "secrets.properties"
// A properties file containing default secret values. This file can be
// checked in version control.
defaultPropertiesFileName = "local.defaults.properties"
}
모든 파일을 저장하고 프로젝트를 Gradle과 동기화합니다.
5. 앱 권한 구성 및 기본 UI 추가
정확한 위치 정보 액세스 권한 요청
Navigation SDK가 작동하려면 GPS 신호에 의존하므로 앱에서 사용자에게 정확한 위치 데이터에 대한 액세스 권한을 부여하도록 요청해야 합니다. AndroidManifest.xml에서 <manifest>
요소의 하위 요소로 정확한 위치에 액세스하는 권한을 추가합니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
/>
</manifest>
Android 위치 정보 액세스 권한에 관한 자세한 내용은 Android 개발자 문서의 위치 정보 액세스 권한 요청 섹션을 참고하세요.
Android 14 기기에서 앱을 실행하려면 정확한 위치 액세스 권한과 동일한 위치에 다음 uses-permission
태그를 추가하여 포그라운드 서비스 위치 권한을 요청하세요.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
기본 UI가 있는 실행 활동 추가
앱이 실행될 때 사용자가 위치 액세스 권한을 부여했는지 확인하고, 권한이 부여되지 않은 경우 권한을 요청하는 가능한 각 시나리오를 처리하기 위해 시작 시 실행되는 코드가 필요합니다. 이렇게 하려면 앱에 기본 사용자 인터페이스를 추가합니다. 이 Codelab에서는 Android 스튜디오에서 새 빈 뷰 활동을 만들 때 생성되는 UI를 사용합니다. 탐색 UI의 활동에 코드를 추가하기 전에 위치 정보 액세스 권한 검사를 실행하도록 이를 조정합니다.
코드 편집기에서 MainActivity.kt
파일을 열고 기본 UI를 보여주는 코드를 검사합니다.
런타임 시 위치 액세스 권한 요청
앱은 Navigation SDK가 초기화되기 전에 정확한 위치에 액세스하기 위한 요청을 트리거해야 합니다.
앱이 시작될 때 이 검사가 실행되도록 하려면 활동의 재정의된 onCreate()
메서드에서 MainActivity
클래스에 코드를 추가합니다.
다음 코드는 사용자가 상세한 위치 정보 액세스 권한을 부여했는지 확인합니다. 권한이 없다면 권한을 요청합니다. onCreate()
메서드 내에 다음 코드를 추가합니다.
val permissions =
if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) {
arrayOf(permission.ACCESS_FINE_LOCATION, permission.POST_NOTIFICATIONS)
} else {
arrayOf(permission.ACCESS_FINE_LOCATION)
}
if (permissions.any { !checkPermissionGranted(it) }) {
if (permissions.any { shouldShowRequestPermissionRationale(it) }) {
// Display a dialogue explaining the required permissions.
}
val permissionsLauncher =
registerForActivityResult(
RequestMultiplePermissions(),
{ permissionResults ->
if (permissionResults.getOrDefault(permission.ACCESS_FINE_LOCATION, false)) {
onLocationPermissionGranted()
} else {
finish()
}
},
)
permissionsLauncher.launch(permissions)
} else {
android.os.Handler(Looper.getMainLooper()).postDelayed({ onLocationPermissionGranted() }, SPLASH_SCREEN_DELAY_MILLIS)
}
}
private fun checkPermissionGranted(permissionToCheck: String): Boolean =
ContextCompat.checkSelfPermission(this, permissionToCheck) == PackageManager.PERMISSION_GRANTED
사용자가 위치 공유 권한을 부여할 때 결과를 처리하는 onLocationPermissionGranted
라는 새 함수를 MainActivity
클래스에 추가합니다. 다음 단계에서는 여기에 코드를 추가하여 새 탐색 활동을 시작합니다.
private fun onLocationPermissionGranted() {
//code to initialize Navigation SDK will go here
}
프로젝트를 빌드합니다. 빌드 오류가 있으면 찾아 수정합니다.
새 가상 기기에서 프로젝트를 실행합니다. 앱을 설치하고 시작할 때 권한 요청 대화상자가 표시됩니다.
6. 탐색 사용자 인터페이스 추가
탐색 UI를 추가하는 방법에는 SupportNavigationFragment
또는 NavigationView
두 가지가 있습니다.
이 Codelab에서는 편의상 NavigationView
를 사용합니다.
레이아웃 수정하기
res/layout/activity_main.xml
를 수정하여 NavigationView의 레이아웃을 추가합니다.
- 파일을 열고 코드 보기로 전환합니다.
- 아래 예와 같이 파일의 전체 콘텐츠를
RelativeLayout
내의 새NavigationView
레이아웃으로 바꿉니다. 앱에 탐색 뷰를 추가하기만 하면 되므로 간단한 레이아웃으로 충분합니다. - NavigationView에 ID '
@+id/navigation_view
'를 지정합니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.libraries.navigation.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
탐색 활동 설정
Android 스튜디오의 편집기에서 MainActivity.kt 파일을 엽니다.
기본 설정 코드를 추가하여 앱에서 탐색 환경이 제대로 작동하도록 하세요. MainActivity.kt 파일에서 다음과 같이 변경합니다.
NavigationView
를 참조하도록MainActivity
클래스에서 변수를 선언합니다.
private lateinit var navView: NavigationView
onCreate()
메서드에 코드를 추가하여NavigationView
참조를 가져옵니다.
navView = findViewById(R.id.navigation_view)
navView.onCreate(savedInstanceState)
- 내비게이션 안내 중에 화면이 꺼지지 않도록
onCreate()
메서드에 코드를 추가합니다.
// Ensure the screen stays on during nav.
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
ViewCompat.setOnApplyWindowInsetsListener
를 호출하여NavigationView
의 ID를 참조하는 코드를 수정합니다.
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.navigation_view)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
- 클래스에
showToast()
메서드를 추가하여 사용자에게 의견을 표시합니다.
private fun showToast(errorMessage: String) {
Toast.makeText(this@MainActivity, errorMessage, Toast.LENGTH_LONG).show()
}
7. Navigation SDK 초기화
기본 탐색 활동 설정을 완료했으므로 이제 Navigation SDK를 초기화할 수 있습니다. 이렇게 하려면 MainActivity.kt 파일에 다음 코드를 추가합니다.
/** Starts the Navigation API, capturing a reference when ready. */
@SuppressLint("MissingPermission")
private fun initializeNavigationApi() {
NavigationApi.getNavigator(
this,
object : NavigatorListener {
override fun onNavigatorReady(navigator: Navigator) {
// store a reference to the Navigator object
mNavigator = navigator
// code to start guidance will go here
}
override fun onError(@NavigationApi.ErrorCode errorCode: Int) {
when (errorCode) {
NavigationApi.ErrorCode.NOT_AUTHORIZED -> {
// Note: If this message is displayed, you may need to check that
// your API_KEY is specified correctly in AndroidManifest.xml
// and is been enabled to access the Navigation API
showToast(
"Error loading Navigation API: Your API key is " +
"invalid or not authorized to use Navigation."
)
}
NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED -> {
showToast(
"Error loading Navigation API: User did not " +
"accept the Navigation Terms of Use."
)
}
else -> showToast("Error loading Navigation API: $errorCode")
}
}
},
)
}
이 코드는 initializeNavigationApi()
라는 새 메서드를 만듭니다. 이 메서드는 NavigationApi.getNavigator()
를 호출하여 Navigator
객체 참조를 가져오고 콜백을 처리하는 NavigatorListener
를 구현합니다.
Navigation API가 초기화되면 NavigationListener.onNavigatorReady
메서드가 호출되며 Navigator
객체가 매개변수로 전달됩니다. 위 코드는 이전에 선언한 mNavigator
변수를 이 메서드에 전달되는 초기화된 Navigator
객체로 업데이트합니다.
마지막으로 onLocationPermissionGranted
메서드에서 initializeNavigationApi
메서드 호출을 추가합니다.
private fun onLocationPermissionGranted() {
initializeNavigationApi()
}
8. 주요 탐색 이벤트의 리스너 추가
사용자가 안내를 따르는 경우 Navigation SDK는 사용자가 경로를 변경하거나 목적지에 도착하는 경우와 같이 경로 중 주요 상태 변경사항을 앱에 알릴 수 있는 이벤트를 실행합니다. MainActivity.kt 파일에 다음 이벤트를 처리할 리스너를 추가합니다.
MainActivity
클래스 내에서 이벤트 리스너 객체를 참조하는 변수를 두 개 선언합니다.
private var arrivalListener: Navigator.ArrivalListener? = null
private var routeChangedListener: Navigator.RouteChangedListener? = null
- 탐색기가 초기화될 때 리스너를 설정하는
registerNavigationListeners()
메서드를 추가합니다. 이 메서드는 도착 이벤트가 발생할 때Navigator.clearDestinations()
를 호출하여NavigationView
를 재설정합니다.
/**
* Registers a number of example event listeners that show an on screen message when certain
* navigation events occur (e.g. the driver's route changes or the destination is reached).
*/
private fun registerNavigationListeners() {
withNavigatorAsync {
arrivalListener =
Navigator.ArrivalListener { // Show an onscreen message
showToast("User has arrived at the destination!")
mNavigator?.clearDestinations()
}
mNavigator?.addArrivalListener(arrivalListener)
routeChangedListener =
Navigator.RouteChangedListener { // Show an onscreen message when the route changes
showToast("onRouteChanged: the driver's route changed")
}
mNavigator?.addRouteChangedListener(routeChangedListener)
}
}
initializeNavigationApi
메서드의onNavigatorReady
콜백 코드에서registerNavigationListeners()
호출을 추가합니다.
override fun onNavigatorReady(navigator: Navigator) {
// store a reference to the Navigator object
mNavigator = navigator
//listen for events en route
registerNavigationListeners()
}
- 사용자 인터페이스를 구성합니다. 안내가 실행 중일 때 탐색 사용자 인터페이스의 다양한 측면을 제어할 수 있습니다. 중요한 맞춤설정 중 하나는 카메라 위치입니다. 다음과 같이
onNavigatorReady
에서navigator
객체 반환의setTaskRemovedBehaviour
메서드 호출을 추가합니다. 이렇게 하면 앱이 스와이프하여 사라질 경우 안내 및 알림이 종료됩니다.
// Disables the guidance notifications and shuts down the app and background service
// when the user dismisses/swipes away the app from Android's recent tasks.
navigator.setTaskRemovedBehavior(Navigator.TaskRemovedBehavior.QUIT_SERVICE)
GoogleMap.followMyLocation
호출을 추가하여CameraPerspective
를 지정합니다.GoogleMap
는 다음과 같이NavigatorView.getMapAsync()
메서드를 통해 액세스됩니다.
navView.getMapAsync {
googleMap ->
googleMap.followMyLocation(GoogleMap.CameraPerspective.TILTED)
}
- 앱 수명 주기 전반에서 탐색이 원활하게 작동하도록 하려면
MainActivity
클래스에서 다음 메서드를 구현하세요.
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
navView.onSaveInstanceState(savedInstanceState)
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
navView.onTrimMemory(level)
}
override fun onStart() {
super.onStart()
navView.onStart()
}
override fun onResume() {
super.onResume()
navView.onResume()
}
override fun onPause() {
navView.onPause()
super.onPause()
}
override fun onConfigurationChanged(configuration: Configuration) {
super.onConfigurationChanged(configuration)
navView.onConfigurationChanged(configuration)
}
override fun onStop() {
navView.onStop()
super.onStop()
}
override fun onDestroy() {
navView.onDestroy()
withNavigatorAsync {
// Unregister event listeners to avoid memory leaks.
if (arrivalListener != null) {
navigator.removeArrivalListener(arrivalListener)
}
if (routeChangedListener != null) {
navigator.removeRouteChangedListener(routeChangedListener)
}
navigator.simulator?.unsetUserLocation()
navigator.cleanup()
}
super.onDestroy()
}
9. 대상 설정
이제 목적지를 설정하고 내비게이션 안내를 시작할 준비가 되었습니다. MainActivity.kt 파일에서 다음과 같이 변경합니다.
- 탐색 대상을 설정하고
placeId
매개변수를 허용하는 새navigateToPlace()
메서드를 추가합니다.
/**
* Requests directions from the user's current location to a specific place (provided by the
* Place ID).
*/
private fun navigateToPlace(placeId: String) {
}
navigateToPlace()
메서드에서Waypoint.builder()
메서드를 사용하여 메서드에 전달된 장소 ID에서Waypoint
를 만듭니다. 장소 ID가 정확한 주소로 확인되지 않는 경우 발생할 수 있는UnsupportedPlaceIdException
를 처리합니다.
val waypoint: Waypoint? =
// Set a destination by using a Place ID (the recommended method)
try {
Waypoint.builder().setPlaceIdString(placeId).build()
} catch (e: Waypoint.UnsupportedPlaceIdException) {
showToast("Place ID was unsupported.")
return
}
navigateToPlace()
메서드에 다음 코드를 추가하여 Waypoint를 사용하여 목적지를 설정합니다.
val pendingRoute = mNavigator?.setDestination(waypoint)
// Set an action to perform when a route is determined to the destination
pendingRoute?.setOnResultListener { code ->
when (code) {
RouteStatus.OK -> {
// Code to start guidance will go here
}
RouteStatus.ROUTE_CANCELED -> showToast("Route guidance canceled.")
RouteStatus.NO_ROUTE_FOUND,
RouteStatus.NETWORK_ERROR ->
// TODO: Add logic to handle when a route could not be determined
showToast("Error starting guidance: $code")
else -> showToast("Error starting guidance: $code")
}
}
Navigator
객체에는 다양한 매개변수를 사용할 수 있는 setDestinations()
메서드가 있습니다. 가장 기본적인 옵션은 Waypoint
를 제공하는 것입니다. 이 설정의 이동 수단은 4륜차에 적합한 DRIVING
(으)로 기본 설정됩니다. setDestinations()
메서드는 RouteStatus
객체가 포함된 ListenableResultFuture
객체를 반환합니다. RouteStatus
는 대상까지의 경로가 발견되었는지 여부를 나타내며, 발견되지 않은 경우 다양한 오류 상태를 처리할 수 있습니다.
- 탐색 사용자 환경을 개선하기 위해 구성을 추가로 변경합니다.
// Hide the toolbar to maximize the navigation UI
supportActionBar?.hide()
// Enable voice audio guidance (through the device speaker)
mNavigator?.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE)
// Simulate vehicle progress along the route (for demo/debug builds)
if (BuildConfig.DEBUG) {
mNavigator?.simulator?.simulateLocationsAlongExistingRoute(
SimulationOptions().speedMultiplier(5f)
)
}
이번 변경사항에는 다음과 같은 개선사항이 포함됩니다.
- 작업 표시줄을 숨겨 탐색 UI의 공간을 최대화합니다.
- 오디오 안내를 사용 설정하여 알림 및 내비게이션 안내를 음성으로 들으세요.
- 속도 배율을 지정하여 디버깅을 위한 시뮬레이터 설정
- 목적지로 사용할 장소 ID를 찾습니다. 이 위치는 사용자 위치에서 그리 멀지 않은 것이 좋습니다. Google Maps Platform Place ID Finder 유틸리티를 사용하거나 Places API 호출에서 장소 ID를 가져옵니다.
탐색을 시뮬레이션하는 경우 코드에서 사용자 위치를 설정하거나 연결된 기기에서 가져올 수 있습니다. 이 Codelab에서는 영국 런던의 위치를 시뮬레이션한다고 가정합니다.
MainActivity
클래스에 컴패니언 객체를 추가하여 시작 위치와 장소 ID를 저장합니다. 이 Codelab에서는 런던의 시작 위치와 트라팔가 광장의 장소 ID를 사용합니다.
companion object{
const val TRAFALGAR_SQUARE ="ChIJH-tBOc4EdkgRJ8aJ8P1CUxo" //London, UK
val startLocation = LatLng(51.345678, -0.1234456)
}
initializeNavigationApi
메서드 내의onNavigatorReady
콜백에서navigateToPlace()
메서드 호출을 추가하고 디버그 모드에서 실행되어 사용자 위치를 설정하는 로직 브랜치를 추가합니다.
// Disables the guidance notifications and shuts down the app and background service
// when the user dismisses/swipes away the app from Android's recent tasks.
navigator.setTaskRemovedBehavior(Navigator.TaskRemovedBehavior.QUIT_SERVICE)
mNavigator = navigator
if (BuildConfig.DEBUG) {
mNavigator?.simulator?.setUserLocation(MainActivity.startLocation)
}
//listen for events en route
registerNavigationListeners()
navView.getMapAsync {
googleMap ->
googleMap.followMyLocation(GoogleMap.CameraPerspective.TILTED)
}
//navigate to a destination
navigateToPlace(MainActivity.TRAFALGAR_SQUARE)
10. 코드 빌드 및 실행
앱을 처음 실행하는 경우 앱에 위치 정보 액세스 권한을 부여하고 Navigation SDK 이용약관에 동의해야 합니다.
참고: 앱을 실행하면 setDestinations() 메서드가 호출되어 처음 1,000개의 대상이 사용된 후 요금이 발생합니다. 자세한 내용은 사용량 및 결제를 참고하세요.
위치 설정
코드에서 위치를 설정했거나 에뮬레이터 속성 대화상자를 사용하지 않는 한 기본적으로 에뮬레이션된 기기의 위치는 캘리포니아 마운틴뷰에 있는 Google 캠퍼스로 설정될 수 있습니다.
이 경우 앱에서 구성한 장소 ID(기본값: 시드니 오페라 하우스, 시드니, 오스트레일리아)로 가는 경로를 찾을 수 없습니다. 이 경우 showToast()
메서드에서 '경로를 찾을 수 없습니다'라는 메시지가 표시됩니다.
시작 위치 하드 코딩
코드에서 다른 위치를 설정하려면 MainActivity.kt의 navigateToPlace()
메서드에서 mNavigator.startGuidance()
호출 전에 다음 줄을 추가합니다.
mNavigator?.simulator?.setUserLocation(startLocation)
선택한 기본 위치에서 에뮬레이터 시작
기기 에뮬레이터에서 다른 위치를 설정하려면 에뮬레이터가 아직 실행되고 있지 않은 경우 에뮬레이터를 시작하고 'Extended Controls' 도움말이 있는 점 3개 메뉴를 클릭합니다. 열리는 대화상자에는 '위치' 메뉴 옵션이 있습니다.
예를 들어 시드니 오페라 하우스의 장소 ID를 목적지로 사용하는 경우 호주 시드니에 있는 위치를 선택합니다. 예를 들어 '본다이 해변'을 검색하고 추천 검색어를 선택한 다음 '위치 저장'을 클릭합니다. 을 클릭합니다. '위치 저장'을 클릭하여 나중에 사용할 수 있도록 저장된 목록에 위치를 추가할 수도 있습니다.
다른 장소 ID를 대상으로 설정하는 경우 시뮬레이션된 경로가 현실적이고 디버깅이 쉬울 만큼 길지 않도록 대상 근처의 위치를 선택합니다.
앱을 다시 시작하면 대상으로 이동합니다.
11. 축하합니다.
이 Codelab을 완료했습니다. 잘하셨습니다. 목적지에 도착하셨습니다. 즐겁게 코딩하세요. :-)
12. 그 외 수행 가능한 작업
앱 개발을 한 단계 더 발전시키고 싶다면 다음 주제를 참고하여 아이디어를 얻어 보세요.
- 추가 탐색 이벤트를 수신 대기합니다. 운전자가 경로를 변경했거나 운전자가 도착했을 때 메시지를 표시하는 코드를 추가합니다.
- 탐색 인터페이스를 맞춤설정합니다.
- 더 어려운 문제가 필요하다면 Places API 장소 선택 도구 컨트롤을 추가하여 사용자가 목적지를 설정할 수 있는지 확인하세요. 힌트: GitHub의 Navigation SDK 데모 앱에는 샘플 구현이 있습니다.
- GitHub의 Navigation SDK 데모 앱에서 사용되는 접근 방식을 채택하여 Navigator 및 GoogleMap 객체를 비동기식으로 호출할 때 발생할 수 있는 문제를 방지합니다. 더 복잡한 앱 시나리오에서는 코드가 실행될 때 이러한 객체의 초기화가 완료되지 않을 수 있습니다. 팁: MainActivity.kt 파일 끝에 InitializedNavScope 클래스를 추가하여 매우 빠르게 구현할 수 있습니다.