iOS でルートをフォローする

プラットフォームを選択: Android iOS JavaScript

乗車を追跡すると、適切な車両の位置情報がユーザーアプリに表示されます。そのため、アプリは、ルートの追跡を開始し、ルートの進行状況を更新し、ルートが完了したら追跡を停止する必要があります。

このドキュメントでは、そのプロセスの仕組みについて説明します。

旅行のフォローを開始する

旅行のフォローを開始する手順は次のとおりです。

  • 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 のコールバックを取得できます。エラー メッセージは、Google Cloud エラーの標準に準拠しています。エラー メッセージの定義とすべてのエラーコードの詳細については、Google Cloud エラーのドキュメントをご覧ください。

乗車中のモニタリングで発生する可能性のある一般的なエラーは次のとおりです。

HTTP RPC 説明
400 INVALID_ARGUMENT クライアントが無効な旅行名を指定しました。旅行名は providers/{provider_id}/trips/{trip_id} の形式にする必要があります。provider_id は、サービス プロバイダが所有する Cloud プロジェクトの ID にする必要があります。
401 UNAUTHENTICATED 有効な認証情報がない場合に、このエラーが表示されます。たとえば、JWT トークンが乗車 ID なしで署名されている場合や、JWT トークンの有効期限が切れている場合などです。
403 PERMISSION_DENIED このエラーは、クライアントに十分な権限がない場合(たとえば、コンシューマー ロールのユーザーが updateTrip を呼び出そうとした場合)、JWT トークンが無効な場合、またはクライアント プロジェクトで API が有効になっていない場合に発生します。JWT トークンがないか、リクエストされた乗車 ID と一致しない乗車 ID でトークンが署名されている可能性があります。
429 RESOURCE_EXHAUSTED リソース割り当てがゼロであるか、トラフィックのレートが上限を超えています。
503 UNAVAILABLE サービス利用不可。通常、サーバーがダウンしています。
504 DEADLINE_EXCEEDED リクエスト期限を超えました。このエラーは、呼び出し元が、メソッドのデフォルト期限よりも短い期限を設定し(つまり、要求された期限はサーバーがリクエストを処理するのに十分ではない)、リクエストがその期限内に完了しなかった場合にのみ発生します。

Consumer SDK のエラーを処理する

Consumer SDK は、コールバック メカニズムを使用して、乗車情報の更新エラーをコンシューマー アプリに送信します。コールバック パラメータは、プラットフォーム固有の戻り値の型(Android では TripUpdateError、iOS では NSError)です。

ステータス コードを抽出する

コールバックに渡されるエラーは通常 gRPC エラーです。ステータス コードの形式で追加情報を抽出することもできます。ステータス コードの完全なリストについては、ステータス コードと gRPC での使用方法をご覧ください。

Swift

NSErrortripModel(_:didFailUpdateTripWithError:) でコールバックされます。

// Called when there is a trip update error.
func tripModel(_ tripModel: GMTCTripModel, didFailUpdateTripWithError error: Error?) {
  // Check to see if the error comes from gRPC.
  if let error = error as NSError?, error.domain == "io.grpc" {
    let gRPCErrorCode = error.code
    ...
  }
}

Objective-C

NSErrortripModel:didFailUpdateTripWithError: でコールバックされます。

// Called when there is a trip update error.
- (void)tripModel:(GMTCTripModel *)tripModel didFailUpdateTripWithError:(NSError *)error {
  // Check to see if the error comes from gRPC.
  if ([error.domain isEqualToString:@"io.grpc"]) {
    NSInteger gRPCErrorCode = error.code;
    ...
  }
}

ステータス コードを解釈する

ステータス コードは、サーバーとネットワーク関連のエラー、クライアントサイドのエラーの 2 種類のエラーを対象としています。

サーバーとネットワークのエラー

次のステータス コードはネットワーク エラーまたはサーバー エラーを示しており、解決するために対応する必要はありません。Consumer SDK は自動的に復元します。

ステータス コード説明
ABORTED サーバーがレスポンスの送信を停止しました。通常、これはサーバーの問題が原因です。
CANCELLED サーバーが送信レスポンスを終了しました。通常、この状態は、
アプリがバックグラウンドに移行したとき、または
Consumer アプリの状態が変化したときに発生します。
INTERRUPTED
DEADLINE_EXCEEDED サーバーの応答に時間がかかりすぎました。
UNAVAILABLE サーバーが利用できませんでした。通常、これはネットワークの問題が原因で発生します。

クライアントエラー

次のステータス コードはクライアント エラーを示しており、解決するには対応が必要です。Consumer SDK は、乗車状況の共有を終了するまで乗車状況の更新を再試行し続けますが、ユーザーが操作するまで復元されません。

ステータス コード説明
INVALID_ARGUMENT Consumer アプリで無効な乗車名を指定しました。乗車名は providers/{provider_id}/trips/{trip_id} 形式に従う必要があります。
NOT_FOUND ルートが作成されなかった。
PERMISSION_DENIED Consumer アプリに十分な権限がありません。このエラーは、次の場合に発生します。
  • Consumer アプリに権限がない
  • Google Cloud コンソールのプロジェクトで Consumer SDK が有効になっていない。
  • JWT トークンがないか、無効です。
  • JWT トークンが、リクエストされた乗車と一致しない乗車 ID で署名されている。
RESOURCE_EXHAUSTED リソース割り当てがゼロであるか、トラフィック フローのレートが速度制限を超えています。
UNAUTHENTICATED JWT トークンが無効なため、リクエストの認証に失敗しました。このエラーは、JWT トークンが乗車 ID なしで署名された場合、または JWT トークンの有効期限が切れた場合に発生します。