Consumer SDK for iOS スタートガイド

Consumer SDK を使用して、オンデマンド配車および配達ソリューションのバックエンド サービスと統合された基本的な一般ユーザー向けアプリを構築して実行できます。有効なルートの表示、ルート更新情報への応答、ルートエラーの処理が可能な Trip and Order Progress アプリを作成できます。

Consumer SDK はモジュラー アーキテクチャであるため、特定のアプリに使用する API の部分を、独自の API、Fleet Engine が提供するバックエンド サービス、Google Maps Platform の追加 API と統合できます。

最小システム要件

  • モバイル デバイスに iOS 14 以降が搭載されている必要があります。
  • Xcode バージョン 15 以降。
  • プロジェクト構成

    Swift Package Manager

    Consumer SDK は Swift Package Manager からインストールできます。SDK を追加するには、既存の Consumer SDK の依存関係がすべて削除されていることを確認します。

    新規または既存のプロジェクトに SDK を追加する手順は次のとおりです。

    1. Xcode の project または workspace を開き、[File] > [Add Package Dependencies] に移動します。
    2. URL として「https://github.com/googlemaps/ios-consumer-sdk」と入力し、Enter キーを押してパッケージを取り込み、[パッケージを追加] をクリックします。
    3. 特定の version をインストールするには、[依存関係ルール] フィールドをバージョン ベースのオプションのいずれかに設定します。新しいプロジェクトの場合は、最新バージョンを指定し、[正確なバージョン] オプションを使用することをおすすめします。完了したら、[パッケージを追加] をクリックします。
    4. [Choose Package Products] ウィンドウで、指定した main ターゲットに GoogleRidesharingConsumer が追加されることを確認します。完了したら、[パッケージを追加] をクリックします。
    5. インストールを確認するには、ターゲットの General ペインに移動します。[Frameworks, Libraries, and Embedded Content] 内に、インストールされているパッケージが表示されます。 [Project Navigator] の [Package Dependencies] セクションで、パッケージとそのバージョンを確認することもできます。

    既存のプロジェクトの package を更新する手順は次のとおりです。

    1. Xcode で、[File] > [Packages] > [Update To Latest Package Versions] に移動します。
    2. インストールを確認するには、Project Navigator の [Package Dependencies] セクションに移動して、パッケージとそのバージョンを確認します。

    CocoaPods を使用して追加された既存の Consumer SDK の依存関係を削除する手順は次のとおりです。

    1. Xcode ワークスペースを閉じます。ターミナルを開いて、次のコマンドを実行します。
      sudo gem install cocoapods-deintegrate cocoapods-clean 
      pod deintegrate 
      pod cache clean --all
    2. CocoaPods 以外に使用していない場合は、PodfilePodfile.resolved、Xcode の workspace を削除します。

    手動でインストールした既存の Consumer SDK を削除する手順は次のとおりです。

    1. Xcode プロジェクトの構成設定で、フレームワーク、ライブラリ、埋め込みコンテンツを見つけます。マイナス記号 (-) を使用して、次のフレームワークを削除します。

      • GoogleRidesharingConsumer.xcframework
    2. Xcode プロジェクトの最上位ディレクトリから、GoogleRidesharingConsumer バンドルを削除します。

    CocoaPods

    CocoaPods を使用して Consumer SDK を構成するには、次のものが必要です。

    • CocoaPods ツール: このツールをインストールするには、ターミナルを開いて次のコマンドを実行します。

      sudo gem install cocoapods
      

    詳しくは、CocoaPods スタートガイドをご覧ください。

    1. Consumer SDK の Podfile を作成し、それを使用して API とその依存関係をインストールします。まず プロジェクトディレクトリに Podfile というファイルを作成しますこのファイルでプロジェクトの依存関係を定義します。次に、Podfile を編集して依存関係を追加します。依存関係を含む例を次に示します。

        source "https://github.com/CocoaPods/Specs.git"
      
        target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
          pod 'GoogleRidesharingConsumer'
        end
      
    2. Podfile を保存します。ターミナルを開き、Podfile があるディレクトリに移動します。

      cd <path-to-project>
      
    3. pod install コマンドを実行します。これにより、Podfile で指定された API と、その依存関係がインストールされます。

      pod install
      
    4. Xcode を終了し、プロジェクトの .xcworkspace ファイルを開いて(ダブルクリックして)Xcode を起動します。後でプロジェクトを開くには、.xcworkspace ファイルを使用します。

    手動インストール

    XCFramework は、Consumer SDK のインストールに使用するバイナリ パッケージです。このパッケージは、M1 チップセットを搭載したマシンなど、複数のプラットフォームで使用できます。このガイドでは、Consumer SDK を含む XCFramework をプロジェクトに手動で追加し、Xcode でビルド設定を構成する方法について説明します。

    SDK のバイナリとリソースをダウンロードします。

    1. 圧縮したファイルを解凍して、XCFramework とリソースにアクセスします。

    2. Xcode を起動し、既存のプロジェクトを開くか、新しいプロジェクトを作成します。iOS を初めて使用する場合は、新しいプロジェクトを作成し、iOS App テンプレートを選択します。

    3. フレームワーク グループがまだ存在しない場合は、プロジェクト グループの下に作成します。

    4. Consumer SDK をインストールするには、プロジェクトの [Frameworks, Libraries, and Embedded Content] に GoogleRidesharingConsumer.xcframework ファイルをドラッグします。プロンプトが表示されたら、[必要に応じてコピー] を選択します。

    5. ダウンロードした GoogleRidesharingConsumer.bundle を Xcode プロジェクトの最上位ディレクトリにドラッグします。プロンプトが表示されたら、[Copy items if needed] を選択します。

    6. プロジェクト ナビゲータからプロジェクトを選択し、アプリケーションのターゲットを選択します。

    7. [Build Phases] タブを開き、[Link Binary with Libraries] で、次のフレームワークとライブラリを追加します(まだ存在しない場合)。

      • Accelerate.framework
      • CoreData.framework
      • CoreGraphics.framework
      • CoreImage.framework
      • CoreLocation.framework
      • CoreTelephony.framework
      • CoreText.framework
      • GLKit.framework
      • ImageIO.framework
      • libc++.tbd
      • libz.tbd
      • Metal.framework
      • OpenGLES.framework
      • QuartzCore.framework
      • SystemConfiguration.framework
      • UIKit.framework
    8. 特定のターゲットではなくプロジェクトを選択し、[Build Settings] タブを開きます。[Other Linker Flags] セクションで、デバッグ用とリリース用の両方に -ObjC を追加します。これらの設定が表示されない場合は、ビルド設定バーのフィルタを [Basic] から [All] に変更します。

    Apple のプライバシー マニフェスト ファイルを追加する

    1. iOS 用 Consumer SDK のプライバシー マニフェスト バンドル(GoogleRidesharingConsumerPrivacy)をダウンロードします。
    2. ファイルを解凍して GoogleRidesharingConsumerPrivacy.bundle にアクセスします。
    3. 以下のいずれかの方法を使用して、GoogleRidesharingConsumerPrivacy.bundle を Xcode プロジェクト ナビゲータに追加します。アプリのターゲットの [ターゲットに追加する] チェックボックスがオンになっていることを確認します。追加すると、PrivacyInfo ファイルがプロジェクト ナビゲータに表示され、値を調べることができます。
    4. Xcode のプライバシー情報のスクリーンショット
    5. アプリのアーカイブを作成し、そのアーカイブからプライバシー レポートを生成して、プライバシー マニフェストが追加されていることを確認します。

    アプリケーションの統合

    認証トークンを提供

    コンシューマ アプリが Fleet Engine のルートの更新情報をリクエストする場合は、リクエストに有効なアクセス トークンを含める必要があります。これらのリクエストを承認して認証するために、Consumer SDK は GMTCAuthorization プロトコルに従ってオブジェクトを呼び出します。オブジェクトは、必要なアクセス トークンを提供する役割を担います。

    トークンの生成方法はアプリ デベロッパーが選択できます。実装では、次の機能を提供する必要があります。

    • HTTPS サーバーからアクセス トークンを(JSON 形式で取得できる)取得します。
    • トークンを解析してキャッシュに保存します。
    • トークンの有効期限が切れたら更新する。

    Fleet Engine サーバーで想定されるトークンの詳細については、認可用の JSON Web Token(JWT)の作成をご覧ください。

    プロバイダ ID は Google Cloud プロジェクト ID と同じです。詳細については、Fleet Engine スタートガイドをご覧ください。

    次の例では、アクセス トークン プロバイダを実装します。

    Swift

    /*
    
        *   SampleAccessTokenProvider.swift
     */
    import GoogleRidesharingConsumer
    
    private let providerURL = "INSERT_YOUR_TOKEN_PROVIDER_URL"
    
    class SampleAccessTokenProvider: NSObject, GMTCAuthorization {
      private struct AuthToken {
        // The cached trip token.
        let token: String
        // Keep track of when the token expires for caching.
        let expiration: TimeInterval
        // Keep track of the trip ID the cached token is for.
        let tripID: String
      }
    
      enum AccessTokenError: Error {
        case missingAuthorizationContext
        case missingData
      }
    
      private var authToken: AuthToken?
    
      func fetchToken(
        with authorizationContext: GMTCAuthorizationContext?,
        completion: @escaping GMTCAuthTokenFetchCompletionHandler
      ) {
        // Get the trip ID from the authorizationContext. This is set by the Consumer SDK.
        guard let authorizationContext = authorizationContext else {
          completion(nil, AccessTokenError.missingAuthorizationContext)
          return
        }
        let tripID = authorizationContext.tripID
    
        // If appropriate, use the cached token.
        if let authToken = authToken,
          authToken.expiration > Date.now.timeIntervalSince1970 && authToken.tripID == tripID
        {
          completion(authToken.token, nil)
          return
        }
    
        // Otherwise, try to fetch a new token from your server.
        let request = URLRequest(url: URL(string: providerURL))
        let task = URLSession.shared.dataTask(with: request) { [weak self] data, _, error in
          guard let strongSelf = self else { return }
          guard error == nil else {
            completion(nil, error)
            return
          }
    
          // Replace the following key values with the appropriate keys based on your
          // server's expected response.
          let tripTokenKey = "TRIP_TOKEN_KEY"
          let tokenExpirationKey = "TOKEN_EXPIRATION"
          guard let data = data,
            let fetchData = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
            let token = fetchData[tripTokenKey] as? String,
            let expiration = fetchData[tokenExpirationKey] as? Double
          else {
            completion(nil, AccessTokenError.missingData)
            return
          }
    
          strongSelf.authToken = AuthToken(token: token, expiration: expiration, tripID: tripID)
          completion(token, nil)
        }
        task.resume()
      }
    }
    

    Objective-C

    /*
    
        *   SampleAccessTokenProvider.h
     */
    #import <Foundation/Foundation.h>
    #import <GoogleRidesharingConsumer/GoogleRidesharingConsumer.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface SampleAccessTokenProvider : NSObject <GMTCAuthorization>
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    /*
    
        *   SampleAccessTokenProvider.m
     */
    #import "SampleAccessTokenProvider.h"
    #import "GoogleRidesharingConsumer/GoogleRidesharingConsumer.h"
    
    static NSString *const PROVIDER_URL = @"INSERT_YOUR_TOKEN_PROVIDER_URL";
    
    // SampleAccessTokenProvider.m
    @implementation SampleAccessTokenProvider {
      // The cached token with claims to the current trip.
      NSString *_cachedTripToken;
      // Keep track of the Trip ID the cached token is for.
      NSString *_lastKnownTripID;
      // Keep track of when tokens expire for caching.
      NSTimeInterval _tokenExpiration;
    }
    
    -   (void)fetchTokenWithContext:(nullable GMTCAuthorizationContext *)authorizationContext
                       completion:(nonnull GMTCAuthTokenFetchCompletionHandler)completion {
      // Get the trip ID from the authorizationContext. This is set by the Consumer SDK.
      NSString *tripID = authorizationContext.tripID;
    
      // Clear cached trip token if trip ID has changed.
      if (![_lastKnownTripID isEqual:tripID]) {
        _tokenExpiration = 0.0;
        _cachedTripToken = nil;
      }
      _lastKnownTripID = tripID;
    
      // Clear cached tripToken if it has expired.
      if ([[NSDate date] timeIntervalSince1970] > _tokenExpiration) {
        _cachedTripToken = nil;
      }
    
      // If appropriate, use the cached token.
      if (_cachedTripToken) {
        completion(_cachedTripToken, nil);
        return;
      }
      // Otherwise, try to fetch a new token from your server.
      NSURL *requestURL = [NSURL URLWithString:PROVIDER_URL];
      NSMutableURLRequest *request =
          [[NSMutableURLRequest alloc] initWithURL:requestURL];
      request.HTTPMethod = @"GET";
    
      // Replace the following key values with the appropriate keys based on your
      // server's expected response.
      NSString *tripTokenKey = @"TRIP_TOKEN_KEY";
      NSString *tokenExpirationKey = @"TOKEN_EXPIRATION";
    
      __weak typeof(self) weakSelf = self;
      void (^handler)(NSData *_Nullable data, NSURLResponse *_Nullable response,
                      NSError *_Nullable error) =
          ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
            typeof(self) strongSelf = weakSelf;
            if (error) {
              completion(nil, error);
              return;
            }
    
            NSError *JSONError;
            NSMutableDictionary *JSONResponse =
                [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&JSONError];
    
            if (JSONError) {
              completion(nil, JSONError);
              return;
            } else {
              // Sample code only. No validation logic.
              id expirationData = JSONResponse[tokenExpirationKey];
              if ([expirationData isKindOfClass:[NSNumber class]]) {
                NSTimeInterval expirationTime = ((NSNumber *)expirationData).doubleValue;
                strongSelf->_tokenExpiration = [[NSDate date] timeIntervalSince1970] + expirationTime;
              }
              strongSelf->_cachedTripToken = JSONResponse[tripTokenKey];
              completion(JSONResponse[tripTokenKey], nil);
            }
          };
      NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
      NSURLSession *mainQueueURLSession =
          [NSURLSession sessionWithConfiguration:config delegate:nil
                                   delegateQueue:[NSOperationQueue mainQueue]];
      NSURLSessionDataTask *task = [mainQueueURLSession dataTaskWithRequest:request completionHandler:handler];
      [task resume];
    }
    
    @end
    

    アプリケーションの初期化

    Swift

    /*
    
        *   AppDelegate.swift
     */
    import GoogleRidesharingConsumer
    import GoogleMaps
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
      func application(_ application: UIApplication,
          didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Register your API key for GMSServices.
        GMSServices.provideAPIKey(yourMapsAPIKey)
    
        // Set the instance of the SampleAccessTokenProvider.
        GMTCServices.setAccessTokenProvider(SampleAccessTokenProvider(), providerID: yourProviderID)
    
        // Other initialization code ...
        return true
      }
    }
    

    Objective-C

    /*
    
        *   AppDelegate.m
     */
    #import <GoogleMaps/GoogleMaps.h>
    #import <GoogleRidesharingConsumer/GoogleRidesharingConsumer.h>
    
    @implementation AppDelegate
    
    -   (BOOL)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      //Register your API key for GMSServices.
      [GMSServices provideAPIKey:yourMapsAPIKey];
    
      //Set the instance of the AccessTokenFactory.
      [GMTCServices setAccessTokenProvider:[[SampleAccessTokenProvider alloc] init]
                                providerID:yourProviderID];
    
      // Other initialization code ...
      return YES;
    }
    
    @end
    

    マップビューの統合

    地図表示を初期化する

    次の例は、GMTCMapView を初期化する方法を示しています。

    Swift

    /*
    
        *   MapViewController.swift
     */
    class ViewController: UIViewController, GMTCMapViewDelegate {
      private var rideSharingMap: GMTCMapView?
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
        self.rideSharingMap = GMTCMapView(frame: UIScreen.main.bounds)
        self.rideSharingMap.delegate = self
        self.rideSharingMap?.settings.myLocationButton = true
        self.view.addSubview(self.rideSharingMap!)
        ...
      }
    

    Objective-C

    /*
    
        *   MapViewController.h
     */
    @interface MapViewController : UIViewController<GMTCMapViewDelegate>
    ...
    @end
    
    /*
    
        *   MapViewController.m
     */
    @implementation MapViewController
    
    -   (void)viewDidLoad {
      [super viewDidLoad];
      ...
      self.mapView = [[GMTCMapView alloc] initWithFrame:CGRectZero];
      self.mapView.settings.myLocationButton = YES;
      self.mapView.delegate = self;
      ...
    }
    
    ...
    
    @end
    

    地図表示イベントを処理する

    次の例は、お客様の状態イベントを処理するデリゲートを実装する方法を示しています。

    Swift

    func mapViewDidInitialize(_ mapview: GMTCMapView) {
      // Handle the update to the state of the map view to browsing.
    }
    
    func mapView(_ mapView: GMSMapView, didTapConsumerMarker mapMarker: GMSMarker, markerType: GMTCMapViewMarkerType) -> Bool {
      // Handle the mapView marker was tapped.
    }
    

    Objective-C

    /*
    
        *   MapViewController.m
     */
    #pragma mark - GMTCMapViewDelegate implementation
    
    // Handle state update of map view.
    
    -   (void)mapViewDidInitializeCustomerState:(GMTCMapView *)mapview {
      // Handle the update to the state of the map view to browsing.
    }
    
    -   (void)mapView:(GMSMapView *)mapView
        didTapConsumerMarker:(nonnull GMSMarker *)mapMarker
                  markerType:(GMTCMapViewMarkerType)markerType {
      // Handle the mapView marker was tapped.
    }
    

    移動経路の共有

    ビューの読み込み後に新しいルートを開始する

    次の例は、ビューが読み込まれた直後に乗車経路の共有を開始する方法を示しています。降車場所や乗車場所などのすべてのユーザー入力を ViewController から収集し、新しい ViewController を作成して乗車の共有を直接開始できます。

    Swift

    /*
    
        *   MapViewController.swift
     */
    override func viewDidLoad() {
      super.viewDidLoad()
      ...
      self.mapView = GMTCMapView(frame: UIScreen.main.bounds)
      self.mapView.delegate = self
      self.view.addSubview(self.mapView)
    }
    
    func mapViewDidInitializeCustomerState(_: GMTCMapView) {
      self.mapView.pickupLocation = self.selectedPickupLocation
      self.mapView.dropoffLocation = self.selectedDropoffLocation
    
      self.startConsumerMatchWithLocations(
        pickupLocation: self.mapView.pickupLocation!,
        dropoffLocation: self.mapView.dropoffLocation!
      ) { [weak self] (tripName, error) in
        guard let strongSelf = self else { return }
        if error != nil {
          // print error message.
          return
        }
        let tripService = GMTCServices.shared().tripService
        // Create a tripModel instance for listening the update of the trip
        // specified by this trip name.
        let tripModel = tripService.tripModel(forTripName: tripName)
        // Create a journeySharingSession instance based on the tripModel
        let journeySharingSession = GMTCJourneySharingSession(tripModel: tripModel)
        // Add the journeySharingSession instance on the mapView for UI updating.
        strongSelf.mapView.show(journeySharingSession)
        // Register for the trip update events.
        tripModel.register(strongSelf)
    
        strongSelf.currentTripModel = tripModel
        strongSelf.currentJourneySharingSession = journeySharingSession
        strongSelf.hideLoadingView()
      }
    
      self.showLoadingView()
    }
    

    Objective-C

    /*
    
        *   MapViewController.m
     */
    -   (void)viewDidLoad {
      [super viewDidLoad];
      ...
      self.mapView = [[GMTCMapView alloc] initWithFrame:CGRectZero];
      self.mapView.delegate = self;
      [self.view addSubview:self.mapView];
    }
    
    // Handle the callback when the GMTCMapView did initialized.
    
    -   (void)mapViewDidInitializeCustomerState:(GMTCMapView *)mapview {
      self.mapView.pickupLocation = self.selectedPickupLocation;
      self.mapView.dropoffLocation = self.selectedDropoffLocation;
    
      __weak __typeof(self) weakSelf = self;
      [self startTripBookingWithPickupLocation:self.selectedPickupLocation
                               dropoffLocation:self.selectedDropoffLocation
                                    completion:^(NSString *tripName, NSError *error) {
                                      __typeof(self) strongSelf = weakSelf;
                                      GMTCTripService *tripService = [GMTCServices sharedServices].tripService;
                                      // Create a tripModel instance for listening to updates to the trip specified by this trip name.
                                      GMTCTripModel *tripModel = [tripService tripModelForTripName:tripName];
                                      // Create a journeySharingSession instance based on the tripModel.
                                      GMTCJourneySharingSession *journeySharingSession =
                                        [[GMTCJourneySharingSession alloc] initWithTripModel:tripModel];
                                      // Add the journeySharingSession instance on the mapView for updating the UI.
                                      [strongSelf.mapView showMapViewSession:journeySharingSession];
                                      // Register for trip update events.
                                      [tripModel registerSubscriber:self];
    
                                      strongSelf.currentTripModel = tripModel;
                                      strongSelf.currentJourneySharingSession = journeySharingSession;
                                      [strongSelf hideLoadingView];
                                    }];
        [self showLoadingView];
    }
    

    アクティブなルートをキャンセルします

    次の例は、現在アクティブなルートをリセットする方法を示しています。

    Swift

    /*
    
        *   MapViewController.swift
     */
    func cancelCurrentActiveTrip() {
      // Stop the tripModel
      self.currentTripModel.unregisterSubscriber(self)
    
      // Remove the journey sharing session from the mapView's UI stack.
      self.mapView.hide(journeySharingSession)
    }
    

    Objective-C

    /*
    
        *   MapViewController.m
     */
    -   (void)cancelCurrentActiveTrip {
      // Stop the tripModel
      [self.currentTripModel unregisterSubscriber:self];
    
      // Remove the journey sharing session from the mapView's UI stack.
      [self.mapView hideMapViewSession:journeySharingSession];
    }
    

    ルートの更新情報をリッスンする

    次の例は、tripModel コールバックを登録する方法を示しています。

    Swift

    /*
    
        *   MapViewController.swift
     */
    override func viewDidLoad() {
      super.viewDidLoad()
      // Register for trip update events.
      self.currentTripModel.register(self)
    }
    

    Objective-C

    /*
    
        *   MapViewController.m
     */
    -   (void)viewDidLoad {
      [super viewDidLoad];
      // Register for trip update events.
      [self.currentTripModel registerSubscriber:self];
      ...
    }
    

    次の例は、tripModel コールバックの登録をキャンセルする方法を示しています。

    Swift

    /*
    
        *   MapViewController.swift
     */
    deinit {
      self.currentTripModel.unregisterSubscriber(self)
    }
    

    Objective-C

    /*
    
        *   MapViewController.m
     */
    -   (void)dealloc {
      [self.currentTripModel unregisterSubscriber:self];
      ...
    }
    

    次の例は、GMTCTripModelSubscriber プロトコルを実装して、ルート状態が更新された際のコールバックを処理する方法を示しています。

    Swift

    /*
    
        *   MapViewController.swift
     */
    func tripModel(_: GMTCTripModel, didUpdate trip: GMTSTrip?, updatedPropertyFields: GMTSTripPropertyFields) {
      // Update the UI with the new `trip` data.
      self.updateUI(with: trip)
    }
    
    func tripModel(_: GMTCTripModel, didUpdate tripStatus: GMTSTripStatus) {
      // Handle trip status did change.
    }
    
    func tripModel(_: GMTCTripModel, didUpdateActiveRouteRemainingDistance activeRouteRemainingDistance: Int32) {
      // Handle remaining distance of active route did update.
    }
    
    func tripModel(_: GMTCTripModel, didUpdateActiveRoute activeRoute: [GMTSLatLng]?) {
      // Handle trip active route did update.
    }
    
    func tripModel(_: GMTCTripModel, didUpdate vehicleLocation: GMTSVehicleLocation?) {
      // Handle vehicle location did update.
    }
    
    func tripModel(_: GMTCTripModel, didUpdatePickupLocation pickupLocation: GMTSTerminalLocation?) {
      // Handle pickup location did update.
    }
    
    func tripModel(_: GMTCTripModel, didUpdateDropoffLocation dropoffLocation: GMTSTerminalLocation?) {
      // Handle drop off location did update.
    }
    
    func tripModel(_: GMTCTripModel, didUpdatePickupETA pickupETA: TimeInterval) {
      // Handle the pickup ETA did update.
    }
    
    func tripModel(_: GMTCTripModel, didUpdateDropoffETA dropoffETA: TimeInterval) {
      // Handle the drop off ETA did update.
    }
    
    func tripModel(_: GMTCTripModel, didUpdateRemaining remainingWaypoints: [GMTSTripWaypoint]?) {
      // Handle updates to the pickup, dropoff or intermediate destinations of the trip.
    }
    
    func tripModel(_: GMTCTripModel, didFailUpdateTripWithError error: Error?) {
      // Handle the error.
    }
    
    func tripModel(_: GMTCTripModel, didUpdateIntermediateDestinations intermediateDestinations: [GMTSTerminalLocation]?) {
      // Handle the intermediate destinations being updated.
    }
    
    func tripModel(_: GMTCTripModel, didUpdateActiveRouteTraffic activeRouteTraffic: GMTSTrafficData?) {
      // Handle trip active route traffic being updated.
    }
    

    Objective-C

    /*
    
        *   MapViewController.m
     */
    #pragma mark - GMTCTripModelSubscriber implementation
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
                didUpdateTrip:(nullable GMTSTrip *)trip
        updatedPropertyFields:(enum GMTSTripPropertyFields)updatedPropertyFields {
      // Update the UI with the new `trip` data.
      [self updateUIWithTrip:trip];
      ...
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel didUpdateTripStatus:(enum GMTSTripStatus)tripStatus {
      // Handle trip status did change.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdateActiveRouteRemainingDistance:(int32_t)activeRouteRemainingDistance {
       // Handle remaining distance of active route did update.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdateActiveRoute:(nullable NSArray<GMTSLatLng *> *)activeRoute {
      // Handle trip active route did update.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdateVehicleLocation:(nullable GMTSVehicleLocation *)vehicleLocation {
      // Handle vehicle location did update.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdatePickupLocation:(nullable GMTSTerminalLocation *)pickupLocation {
      // Handle pickup location did update.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdateDropoffLocation:(nullable GMTSTerminalLocation *)dropoffLocation {
      // Handle drop off location did update.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel didUpdatePickupETA:(NSTimeInterval)pickupETA {
      // Handle the pickup ETA did update.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdateRemainingWaypoints:(nullable NSArray<GMTSTripWaypoint *> *)remainingWaypoints {
      // Handle updates to the pickup, dropoff or intermediate destinations of the trip.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel didUpdateDropoffETA:(NSTimeInterval)dropoffETA {
      // Handle the drop off ETA did update.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel didFailUpdateTripWithError:(nullable NSError *)error {
      // Handle the error.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdateIntermediateDestinations:
            (nullable NSArray<GMTSTerminalLocation *> *)intermediateDestinations {
      // Handle the intermediate destinations being updated.
    }
    
    -   (void)tripModel:(GMTCTripModel *)tripModel
        didUpdateActiveRouteTraffic:(nullable GMTSTrafficData *)activeRouteTraffic {
      // Handle trip active route traffic being updated.
    }
    

    エラー処理

    tripModel を登録しているときにエラーが発生した場合は、デリゲート メソッド tripModel(_:didFailUpdateTripWithError:) を実装して tripModel のコールバックを取得できます。Fleet Engine は、Google Cloud のエラー標準に沿ったエラー メッセージを生成しました。詳細なエラー メッセージの定義とすべてのエラーコードについては、Google Cloud のエラーのドキュメントをご覧ください。

    特に、ルートのモニタリングでは、有効な認証トークンを提供する必要があります。トークンが期限切れになっているなど、有効な認証情報がない場合、401 UNAUTHENTICATED が発生します。呼び出し元に特定の API を呼び出す権限がない場合(コンシューマ ロールを持つユーザーが updateTrip を呼び出そうとした場合など)、またはリクエストに JWT トークンに有効な車両 ID/trip_id が含まれていない場合は、403 PERMISSION_DENIED が発生します。

    詳細については、コンシューマ SDK のエラー処理をご覧ください。

    UI のカスタマイズ

    カスタム ポリラインの UI オプションを取得および設定する

    次の例は、ポリラインのカスタム UI オプションを設定する方法を示しています。

    Swift

    /** MapViewController.swift */
    
    func updatePolylineUIOptions() {
      // The polyline type that you would like to set custom UI options for.
      let customizablePolylineType = GMTCPolylineType.activeRoute
    
      let polylineStyleOptions = GMTCMutablePolylineStyleOptions()
      polylineStyleOptions.strokeWidth = 8.0
      polylineStyleOptions.strokeColor = .blue
      polylineStyleOptions.isVisible = true
      polylineStyleOptions.zIndex = 1000
      polylineStyleOptions.isGeodesic = true
      let coordinator = self.mapView.consumerMapStyleCoordinator
      coordinator.setPolylineStyleOptions(polylineStyleOptions, polylineType:customizablePolylineType)
    }
    

    Objective-C

    /** MapViewController.m */
    
    -   (void)updatePolylineUIOptions {
      // The polyline type that you would like to set custom UI options for.
      GMTCPolylineType customizablePolylineType = GMTCPolylineTypeActiveRoute;
    
      GMTCMutablePolylineStyleOptions *polylineStyleOptions =
          [[GMTCMutablePolylineStyleOptions alloc] init];
      polylineStyleOptions.strokeWidth = 8.0;
      polylineStyleOptions.strokeColor = [UIColor blueColor];
      polylineStyleOptions.isVisible = YES;
      polylineStyleOptions.zIndex = 1000;
      polylineStyleOptions.isGeodesic = YES;
      [[_mapView consumerMapStyleCoordinator] setPolylineStyleOptions:polylineStyleOptions
                                                    polylineType:customizablePolylineType];
    }
    

    カスタム マーカーの UI オプションを取得および設定する

    次の例は、マーカーのカスタム UI オプションを設定する方法を示しています。

    Swift

    /** MapViewController.swift */
    
    func updateMarkerUIOptions() {
      let customizableMarkerType = GMTCCustomizableMarkerType.tripVehicle
      let markerStyleOptions = GMTCMutableMarkerStyleOptions()
      markerStyleOptions.groundAnchor = groundAnchor
      markerStyleOptions.isVisible = true
      markerStyleOptions.icon = icon
      markerStyleOptions.zIndex = 100
      markerStyleOptions.isFlat = false
      let coordinator = self.mapView.consumerMapStyleCoordinator
      coordinator.setMarkerStyleOptions(markerStyleOptions, markerType: customizableMarkerType)
    }
    

    Objective-C

    /** MapViewController.m */
    
    -   (void)updateMarkerUIOptions {
      // The marker type that you would like to set custom UI options for.
      GMTCCustomizableMarkerType customizableMarkerType = GMTCCustomizableMarkerTypeTripVehicle;
    
      GMTCMutableMarkerStyleOptions *markerStyleOptions =
          [[GMTCMutableMarkerStyleOptions alloc] init];
      markerStyleOptions.groundAnchor = groundAnchor;
      markerStyleOptions.isVisible = YES;
      markerStyleOptions.icon = icon;
      markerStyleOptions.zIndex = 100;
      markerStyleOptions.isFlat = NO;
    
      [[_mapView consumerMapStyleCoordinator] setMarkerStyleOptions:markerStyleOptions markerType:customizableMarkerType];
    }
    

    カメラのズームの調整

    Maps SDK for iOS の [現在地] ボタンでは、カメラの位置がデバイスの位置に設定されます。

    移動経路の共有セッションがアクティブな場合は、カメラを中央に配置して、デバイスの位置情報だけでなく、移動に焦点を合わせることができます。

    Consumer SDK には、デフォルトで有効になっている自動カメラ機能が用意されています。ジャーニーを共有するルートと次のルートの地点にフォーカスするようにカメラがズームします。

    AutoCamera

    カメラの動作をより細かく制御する必要がある場合は、isAllowCameraAutoUpdate プロパティを使用して、自動カメラ機能を無効または有効にできます。

    カメラのカスタマイズについて詳しくは、Maps SDK for iOS のカメラを移動するをご覧ください。