Google Maps Platform Navigation SDK로 Swift에서 간단한 iOS 내비게이션 앱 빌드

1. 시작하기 전에

이 Codelab에서는 Google Maps Platform Navigation SDK를 사용하여 사전 구성된 목적지로 이동하는 간단한 iOS 앱을 만드는 방법을 알아봅니다.

완료되면 앱은 다음과 같이 표시됩니다.

7e7c194a98d6dfa4.png

기본 요건

학습할 내용

  • Navigation SDK를 사용하여 목적지로 이동하는 간단한 iOS Swift 앱을 만드는 방법
  • 원격 Cocoapods 저장소에서 Navigation SDK를 통합하는 방법
  • Navigation SDK 최종 사용자 약관에 대한 위치 권한 및 사용자 동의를 관리하는 방법
  • SDK를 초기화하는 방법
  • 목적지를 설정하고 내비게이션 안내를 시작하는 방법

필요한 항목

  • XCode의 최신 안정화 버전
  • 결제가 사용 설정된 Google 계정 및 프로젝트
  • iOS 기기 또는 XCode 시뮬레이터에서 실행되는 에뮬레이터 기기 어떤 방법을 선택하든 Navigation SDK의 최소 요구사항을 충족해야 합니다.

2. 설정

Google Cloud Platform 계정 및 결제가 사용 설정된 프로젝트가 없는 경우 Google Maps Platform 시작하기 안내에 따라 Google Cloud 프로젝트를 설정합니다.

콘솔에서 Google Cloud 프로젝트 선택

Cloud Console에서 프로젝트 드롭다운 메뉴를 클릭하고 이 Codelab에 사용할 프로젝트를 선택합니다.

Google Cloud 콘솔의 프로젝트 선택기 드롭다운 메뉴

프로젝트에서 Navigation SDK 사용 설정

Google Cloud Marketplace에서 이 Codelab에 필요한 Google Maps Platform API 및 SDK를 사용 설정합니다.

Google Cloud 콘솔에서 API 및 서비스 > 라이브러리로 이동하여 'Navigation SDK'를 검색합니다.

검색 결과가 하나 표시됩니다.

Google Cloud 콘솔의 API 라이브러리 화면에 Navigation SDK 페이지가 표시되어 있습니다.

Navigation SDK를 클릭하여 제품 세부정보 페이지를 엽니다. 사용 설정을 클릭하여 프로젝트에서 SDK를 사용 설정합니다.

iOS용 Google Maps SDK에 대해서도 이 과정을 반복합니다.

API 키 만들기

Cloud Console의 사용자 인증 정보 페이지에서 API 키를 생성합니다. Google Maps Platform에 대한 모든 요청에는 API 키가 필요합니다. 콘솔의 사용자 인증 정보 페이지 페이지 상단에서 '+사용자 인증 정보 만들기'를 클릭하고 옵션에서 'API 키'를 선택합니다.

프로덕션용으로는 API 키의 애플리케이션 제한을 설정하는 것이 좋지만 이 Codelab에서는 선택사항입니다.

3. 샘플 프로젝트 파일 가져오기

이 섹션에서는 이 Codelab의 GitHub 저장소에서 파일을 클론하여 기본 빈 Xcode 앱 프로젝트를 설정하는 방법을 설명합니다. GitHub 저장소에는 Codelab 코드의 이전 버전과 이후 버전이 포함되어 있습니다. Codelab은 빈 프로젝트 템플릿으로 시작하여 완성된 상태로 빌드됩니다. 막히는 부분이 있으면 저장소의 완료된 프로젝트를 참고하세요.

저장소 클론 또는 코드 다운로드

코드랩을 저장할 디렉터리로 이동합니다.

그런 다음 저장소를 클론하거나 코드를 다운로드합니다.

git clone https://github.com/googlemaps-samples/codelab-navigation-101-ios-swift

git이 설치되어 있지 않은 경우 이 버튼을 클릭하여 코드를 가져오세요.

빠르게 시작할 수 있도록 저장소의 Starter 폴더에는 이 Codelab을 따라 하는 데 도움이 되는 시작 코드가 포함되어 있습니다. 언제든지 앞으로 건너뛰거나 진행 상황을 확인할 수 있도록 완성된 Solution 프로젝트도 있습니다. 솔루션 프로젝트를 사용하려면 아래의 'Cocoapods를 사용하여 설치' 안내를 따른 후 solution/Navigation SDK Codelab 폴더에서 'pod update' 명령어를 실행해야 합니다.

리포지토리를 로컬에 클론한 후 XCode를 사용하여 Starter 폴더를 기존 프로젝트로 엽니다. 프로젝트가 빌드되고 실행되는지 확인합니다.

기기 연결 또는 XCode 시뮬레이터 설정

4. 앱에 Navigation SDK 추가

Navigation SDK를 Xcode 프로젝트에 통합하는 방법은 세 가지가 있습니다. 이 Codelab에서는 CocoaPods를 사용합니다. Swift Package Manager를 사용하여 통합하는 방법 또는 SDK를 다운로드하여 수동으로 설치하는 방법에 관한 자세한 내용은 Navigation SDK 문서의 Xcode 프로젝트 생성 및 Navigation SDK 설치를 참고하세요.

Cocoapods를 사용하여 설치

아직 CocoaPods 도구가 없으면 터미널에서 다음 명령어를 실행하여 macOS에 CocoaPods 도구를 설치합니다. 자세한 내용은 CocoaPods 시작 가이드를 참고하세요.

sudo gem install cocoapods

starter/Navigation SDK Codelab 폴더 내 프로젝트 폴더에 Podfile이라는 새 파일을 만듭니다 (XCode에서 File > New > File > Other > Empty를 선택하고 'Podfile'로 저장).

Podfile에 다음 콘텐츠를 추가합니다.

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '15.0'

target 'Navigation SDK Codelab' do
  pod 'GoogleNavigation', '9.1.1'
end

Podfile 할인을 받으세요.

터미널을 열고 Podfile을 저장한 위치로 디렉터리를 변경합니다 (Codelab 저장소의 'starter/Navigation SDK Codelab' 폴더여야 함).

cd "<path-to-starter-project-folder>/Navigation SDK Codelab"

pod install 명령어를 실행합니다. Podfile에 지정된 API가 API에 포함된 종속 항목과 함께 설치됩니다.

pod install

Xcode를 닫은 다음 프로젝트의 .xcworkspace 파일을 열어 Xcode를 실행합니다. 이 때부터는 .xcworkspace 파일을 사용하여 프로젝트를 열어야 합니다.

Pods 디렉터리가 프로젝트 구조에 추가되었으며 'GoogleMaps' 및 'GoogleNavigation' Pod가 포함되어 있는지 확인합니다.

6e81772ee067d452.png

API 키 추가

다음과 같이 API 키를 AppDelegate.swift에 추가합니다.

  1. 다음 import 문을 추가합니다.
import GoogleMaps
import GoogleNavigation
  1. application(_:didFinishLaunchingWithOptions:) 메서드에 다음을 추가합니다.
GMSServices.provideAPIKey("YOUR_API_KEY")

'YOUR_API_KEY'를 이전 단계에서 만든 API 키로 바꿉니다.

프로젝트를 빌드하고 오류를 수정합니다.

5. 앱 권한 구성

Navigation SDK는 GPS 신호를 사용하여 도로에 스냅된 위치와 세부 경로 안내를 제공하므로 앱에서 사용자에게 정확한 위치 데이터에 대한 액세스 권한을 부여하도록 요청해야 합니다.

이렇게 하려면 Xcode에서 앱의 Info.plist에 몇 가지 속성을 추가하고, 런타임에 사용자에게 권한을 요청하는 코드를 앱에 추가하고, 권한이 부여되지 않거나 위치를 사용할 수 없는 등의 오류를 처리해야 합니다.

Xcode에서 Info.plist를 엽니다. 모습은 다음과 유사합니다.

6532a85bd9ac8fb4.png

정확한 위치 정보 액세스 권한 요청

'정보 속성 목록' 행 위로 마우스 포인터를 가져가면 '+' 아이콘이 표시됩니다. 이 아이콘을 클릭하여 새 값을 추가할 수 있습니다. '+'를 클릭하면 추천 속성 이름이 포함된 대화상자가 표시되지만 속성을 수동으로 추가할 수도 있습니다.

Info.plist에 다음 속성과 값을 추가합니다.

속성

개인 정보 보호 - 위치 항상 및 사용 중 사용 설명

'이 앱은 세부 경로를 안내하는 내비게이션을 제공하기 위해 기기 위치가 필요합니다.'

개인 정보 보호 - 사용 중 위치 사용 설명

'이 앱은 세부 경로를 안내하는 내비게이션을 제공하기 위해 기기 위치가 필요합니다.'

allowsBackgroundLocationUpdates

백그라운드 위치 정보 액세스 권한 요청

Info.plist에 다음 속성과 값을 추가합니다.

UIBackgroundModes > 행 추가 > Item 0: App registers for location updates (제안 드롭다운 목록에서 이 값을 선택)

완료되면 Info.plist는 다음과 같이 표시됩니다.

3b0c49018451d0ff.png

런타임 시 위치 정보 액세스 권한 요청

ViewController.swift에 다음 import 문을 추가합니다.

import GoogleNavigation

ViewController 클래스에 다음 선언을 추가합니다.

var locationManager: CLLocationManager!

loadView()의 메서드 재정의를 추가하고 locationManager.requestAlwaysAuthorization()를 호출합니다.

override func loadView() {
        locationManager = CLLocationManager()
        locationManager.requestAlwaysAuthorization()

이제 앱이 사용자에게 위치를 요청하고 사용자가 권한을 부여하면 앱에서 위치를 사용할 수 있습니다 .

알림을 표시할 권한 요청

loadView()에 다음 코드를 추가하여 사용자에게 알림을 표시할 권한을 요청합니다. 이는 탐색 조작 안내를 표시하는 데 필요합니다.

UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
        granted, error in
        // Handle denied authorization to display notifications.
          if !granted || error != nil {
              print("User rejected request to display notifications.")
          }
        }

앱을 빌드하고 실행하여 위치를 공유하고 알림을 사용 설정하라는 메시지가 표시되는지 확인합니다.

ad5f665a21170c49.png

6. 탐색 사용자 인터페이스 추가

이 단계에서는 지도를 추가하고 위치를 표시하도록 구성합니다. 그런 다음 사용자에게 Navigation SDK 이용약관이 포함된 대화상자를 표시합니다.

앱에 지도 뷰 추가

ViewController에서 GMSMapView 변수를 선언하려면 다음 줄을 추가합니다.

var mapView: GMSMapView!

Viewcontroller.swiftloadView()에 다음 코드를 추가하여 지도를 초기화합니다.

let camera = GMSCameraPosition.camera(withLatitude: 51.483174, longitude: -0.177369, zoom: 14)
let options = GMSMapViewOptions()
options.camera = camera
options.frame = .zero
        
mapView = GMSMapView(options: options)
view = mapView

앱을 빌드하고 실행하면 런던 남서부를 중심으로 한 지도가 표시됩니다.

1d46ce5c0851cae3.png

Navigation SDK 제품 이용약관 대화상자 표시

이전 코드와 동일한 loadView() 메서드의 ViewController.swift에 다음 코드를 추가합니다. 그러면 Navigation SDK 최종 사용자 이용약관이 표시됩니다. 수락하지 않으면 탐색이 사용 설정되지 않습니다.

// Show the terms and conditions.
let companyName = "Navigation SDK Codelab"
GMSNavigationServices.showTermsAndConditionsDialogIfNeeded(withCompanyName: companyName) { termsAccepted in
  if termsAccepted {
    // Enable navigation if the user accepts the terms.
    self.mapView.isNavigationEnabled = true
    // Request authorization for alert notifications which deliver guidance instructions
    // in the background.
  } else {
    // Handle the case when the user rejects the terms and conditions.
  }
}

앱을 빌드하고 실행하여 대화상자를 확인합니다.

29f17ae5b4c07c9f.png

7. 키 탐색 이벤트 리스너 추가

이 단계에서는 목적지 도착이나 운전자 경로 변경과 같은 주요 이벤트의 리스너를 설정하는 방법을 보여줍니다.

이러한 이벤트를 수신하려면 뷰 컨트롤러가 GMSNavigatorListener 프로토콜을 채택해야 합니다.

이 프로토콜을 ViewController.swift의 클래스 정의에 추가합니다.

class ViewController: UIViewController,
                      GMSNavigatorListener {

이제 loadView():에서 리스너를 설정하는 코드 줄을 추가합니다.

// Add a listener for GMSNavigator.
mapView.navigator?.add(self)

마지막으로 발생하는 이벤트를 처리하는 두 메서드를 클래스에 추가합니다.

// Listener to handle arrival events.
func navigator(_ navigator: GMSNavigator, didArriveAt waypoint: GMSNavigationWaypoint) {
  print("You have arrived at: \(waypoint.title)")
}

// Listener for route change events.
func navigatorDidChangeRoute(_ navigator: GMSNavigator) {
  print("The route has changed.")
}

8. 목적지 설정 및 안내 시작

이 섹션에서는 목적지를 설정하고 내비게이션 안내를 시작하는 방법을 알아봅니다.

탐색 로직을 위한 새 함수를 만듭니다.

먼저 ViewControllerstartNav()라는 새 함수를 추가합니다. 여기에는 목적지를 설정하고 탐색을 시작하는 로직이 포함됩니다.

// Create a route and start guidance.
@objc func startNav() {
}

대상Waypoint를 만듭니다.

그런 다음 웨이포인트가 하나 있는 대상 배열을 만듭니다.

// Create a route and start guidance.
@objc func startNav() {
  var destinations = [GMSNavigationWaypoint]()
  destinations.append(
    GMSNavigationWaypoint.init(
      placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
      title: "Trafalgar Square")!)
}

setDestinations()을 호출하고 응답을 처리합니다.

그런 다음 setDestinations를 호출하고 반환된 GMSRouteStatus를 처리합니다.

GMSRouteStatus가 'OK'이면 mapViewnavigator 객체에 isGuidanceActive=true을 설정하여 안내를 시작합니다. 그렇지 않으면 오류가 발생했음을 보여주는 문을 출력합니다.

반환된 GMSRouteStatus 값이 'OK'이면 mapView.locationSimulator.simulateLocationsAlongExistingRoute()을 호출하여 경로를 따라 운전하는 시뮬레이션을 시작합니다.

// Create a route and start guidance.
@objc func startNav() {
  var destinations = [GMSNavigationWaypoint]()
    destinations.append(
      GMSNavigationWaypoint.init(
        placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
          title: "Trafalgar Square")!)
      
  mapView.navigator?.setDestinations(
    destinations
  ) { routeStatus in
    guard routeStatus == .OK else {
      print("Handle route statuses that are not OK.")
      return
    }
    //If routeStatus is OK, start guidance.
    self.mapView.navigator?.isGuidanceActive = true
    //start simulating driving along the route. self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
    self.mapView.cameraMode = .following
  }
}

일반적인 오류 상태 처리

특히 새 앱의 초기 문제를 디버깅할 때는 GMSRouteStatus 오류를 더 명시적으로 처리하는 것이 유용합니다. 예를 들어 디버그 설정으로 인해 처음에는 위치 권한, API 키 또는 '경로를 찾을 수 없음' 오류가 더 자주 발생할 수 있으므로 이러한 오류 상태를 처리하는 것이 유용할 수 있습니다.

이러한 특정 사례를 처리하고 콘솔에 문을 출력하는 코드를 추가합니다.

mapView.navigator?.setDestinations(
  destinations
) { routeStatus in
    guard routeStatus == .OK else {
      print("Handle route statuses that are not OK.")
      switch routeStatus {
       case .locationUnavailable:
        print("Location unavailable.") //check permissions
      case .noRouteFound:
        print("No route found.") //check start location and destination
      case .waypointError:
        print("Waypoint error") //check Place ID
      default:
        print("Not sure what happened")
      }
    return
  }

내비게이션 안내를 시작하는 버튼 추가

마지막으로 UI에 버튼을 추가하고 startNav 메서드에 연결합니다. 다음 코드를 사용하여 makeButton() 메서드를 만듭니다. loadView()에서 makeButton() 함수를 호출합니다.

// Add a button to the view.
func makeButton() {
  // A button to start navigation.
  let navButton = UIButton(frame: CGRect(x: 5, y: 150, width: 200, height: 35))
  navButton.backgroundColor = .blue
  navButton.alpha = 0.5
  navButton.setTitle("Start navigation", for: .normal)
  navButton.addTarget(self, action: #selector(startNav), for: .touchUpInside)
  self.mapView.addSubview(navButton)
}

앱을 빌드하고 실행합니다.

참고:

startNav()

다음과 같이 호출됩니다.

setDestinations()

사용된 첫 1,000개의 대상 이후에 요금이 청구되는 메서드입니다. 자세한 내용은 사용량 및 결제를 참고하세요.

9. 축하합니다.

잘하셨습니다. 목적지에 도착했습니다.

7a69dcb75c904d7.png

Google Maps Platform Navigation SDK를 사용하여 목적지까지의 세부 경로 안내를 제공하는 간단한 앱을 만들었습니다.

앱 권한과 Navigation SDK 최종 사용자 약관 대화상자를 구성하고 장소 ID를 사용하여 목적지를 지정했습니다. 앱에서 다양한 성공 및 오류 상태를 처리했습니다.

10. 그 외 수행 가능한 작업

앱 개발을 더 진행하고 싶다면 다음 주제에서 아이디어를 얻으세요.

  • 더 많은 탐색 이벤트 수신 대기 남은 시간이나 거리가 기준점을 초과하는 경우 메시지를 표시하는 코드를 추가합니다.
  • 탐색 인터페이스를 맞춤설정합니다.
  • 더 큰 과제를 원한다면 사용자가 목적지를 설정할 수 있도록 Places API 장소 선택기를 추가해 보세요. 힌트: Navigation SDK 데모 앱에는 샘플 구현이 있습니다. 프로젝트 폴더에서 pod try GoogleNavigation를 실행하여 코드를 확인합니다.