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 Simulator で実行されているエミュレートされたデバイス。どちらを選択する場合でも、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」を検索します。

検索結果が 1 件表示されます。

Google Cloud コンソールの [API ライブラリ] 画面。Navigation SDK ページが表示されています。

[Navigation SDK] をクリックして、[プロダクトの詳細] ページを開きます。[有効にする] をクリックして、プロジェクトで SDK を有効にします。

Google Maps SDK for iOS についてもこのプロセスを繰り返します。

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 がインストールされていない場合は、次のボタンをクリックしてコードを取得します。

できるだけ早く演習を開始できるように、この Codelab で使用できるスターター コードが Starter フォルダに用意されています。また、いつでも先に進んだり、進捗状況を確認したりできるように、完成した Solution プロジェクトも用意されています。ソリューション プロジェクトを使用するには、以下の「Cocoapods を使用してインストールする」の手順に沿って操作し、solution/Navigation SDK Codelab フォルダから「pod update」コマンドを実行する必要があります。

リポジトリのローカルクローンを作成したら、XCode を使用して Starter フォルダを既存のプロジェクトとして開きます。プロジェクトがビルドされて実行されることを確認します。

デバイスを接続するか、XCode シミュレータをセットアップする

4. アプリに Navigation SDK を追加する

Navigation SDK を XCode プロジェクトに統合する方法は 3 つあります。この 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 とその依存関係がインストールされます。

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

実行時に位置情報へのアクセスをリクエストする

次の import ステートメントを ViewController.swift に追加します。

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)

最後に、発生したイベントを処理する 2 つのメソッドをクラスに追加します。

// 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 を作成します。

次に、1 つの経由地を含む宛先の配列を作成します。

// 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 のエンドユーザー規約ダイアログを設定し、Place ID を使用して目的地を指定している。アプリでさまざまな成功状態とエラー状態を処理しました。

10. さらに活用する

アプリ開発をさらに進めたい場合は、次のトピックを参考にしてください。