Когда вы отслеживаете поездку, ваше приложение отображает потребителю местоположение соответствующего транспортного средства. Для этого приложению необходимо начать отслеживать поездку, обновить ход поездки и прекратить отслеживать поездку после её завершения.
В этом документе описывается, как работает этот процесс.
Начать следить за поездкой
Вот как можно начать следить за поездкой:
Собирайте все пользовательские данные, такие как места высадки и посадки, из
ViewController.Создайте новый
ViewController, чтобы начать отслеживать поездку напрямую.
В следующем примере показано, как начать отслеживать поездку сразу после загрузки представления.
Быстрый
/*
 * 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];
}
Остановить отслеживание поездки
Вы прекращаете отслеживать поездку, когда она завершена или отменена. В следующем примере показано, как прекратить публикацию активной поездки.
Быстрый
/*
 * 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 . 
Быстрый
/*
 * 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 . 
Быстрый
/*
 * MapViewController.swift
 */
deinit {
  self.currentTripModel.unregisterSubscriber(self)
}
Objective-C
/*
 * MapViewController.m
 */
- (void)dealloc {
  [self.currentTripModel unregisterSubscriber:self];
  ...
}
Пример обработки обновлений поездки
 В следующем примере показано, как реализовать протокол GMTCTripModelSubscriber для обработки обратных вызовов при обновлении состояния поездки. 
Быстрый
/*
 * 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 , реализовав метод делегата tripModel(_:didFailUpdateTripWithError:) . Сообщения об ошибках соответствуют стандарту Google Cloud Error. Подробные определения сообщений об ошибках и все коды ошибок см. в документации Google Cloud Errors .
Вот некоторые распространенные ошибки, которые могут возникнуть при мониторинге поездки:
| HTTP | RPC | Описание | 
|---|---|---|
| 400 | НЕВЕРНЫЙ_АРГУМЕНТ |  Клиент указал недопустимое название поездки. Название поездки должно иметь формат providers/{provider_id}/trips/{trip_id} . В качестве provider_id должен быть указан идентификатор облачного проекта, принадлежащего поставщику услуг. | 
| 401 | НЕ ПОДТВЕРЖДЕНО | Эта ошибка возникает, если отсутствуют действительные учётные данные аутентификации. Например, если токен JWT подписан без идентификатора поездки или срок действия токена JWT истёк. | 
| 403 | ДОСТУП ЗАПРЕЩЕН | Эта ошибка возникает, если у клиента недостаточно прав (например, пользователь с ролью потребителя пытается вызвать updateTrip), если токен JWT недействителен или API не включен для клиентского проекта. Возможно, токен JWT отсутствует или токен подписан идентификатором поездки, не соответствующим запрошенному идентификатору поездки. | 
| 429 | RESOURCE_EXHAUSTED | Квота ресурсов равна нулю или скорость трафика превышает лимит. | 
| 503 | НЕДОСТУПНО | Сервис недоступен. Обычно сервер не работает. | 
| 504 | DEADLINE_EXCEEDED | Превышен срок выполнения запроса. Эта ошибка возникает только в том случае, если вызывающий объект устанавливает срок, который короче срока выполнения метода по умолчанию (то есть запрошенного срока недостаточно для обработки запроса сервером), и запрос не был завершён в установленный срок. | 
Обработка ошибок Consumer SDK
 Consumer SDK отправляет ошибки обновления данных о поездках в приложение Consumer с помощью механизма обратного вызова. Параметр обратного вызова имеет тип возвращаемого значения, зависящий от платформы ( TripUpdateError на Android и NSError на iOS).
Извлечь коды статуса
Ошибки, передаваемые в функцию обратного вызова, обычно являются ошибками gRPC, и вы также можете извлечь из них дополнительную информацию в виде кода состояния. Полный список кодов состояния см. в разделе Коды состояния и их использование в gRPC .
Быстрый
 NSError вызывается обратно в tripModel(_: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
 NSError вызывается обратно в tripModel: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;
    ...
  }
}
Интерпретировать коды статуса
Коды состояния охватывают два вида ошибок: ошибки, связанные с сервером и сетью, и ошибки на стороне клиента.
Ошибки сервера и сети
Следующие коды состояния соответствуют ошибкам сети или сервера, и вам не нужно предпринимать никаких действий для их устранения. Consumer SDK автоматически устраняет их.
| Код статуса | Описание | 
|---|---|
| ПРЕРВАНО | Сервер перестал отправлять ответ. Обычно это вызвано проблемами на сервере. | 
| ОТМЕНЕНО |  Сервер прервал исходящий ответ. Обычно это происходит, когда приложение отправляется в фоновый режим или когда происходит изменение состояния Потребительское приложение.  | 
| ПРЕРВАН | |
| DEADLINE_EXCEEDED | Сервер слишком долго не отвечал. | 
| НЕДОСТУПНО | Сервер был недоступен. Обычно это происходит из-за проблем с сетью. | 
Ошибки клиента
Следующие коды состояния относятся к ошибкам клиента, и вам необходимо принять меры для их устранения. Consumer SDK продолжит попытки обновить данные о поездке, пока вы не завершите обмен данными о поездке, но не восстановится, пока вы не примете меры.
| Код статуса | Описание | 
|---|---|
| НЕВЕРНЫЙ_АРГУМЕНТ |  Приложение Consumer указало недопустимое название поездки. Название поездки должно иметь формат providers/{provider_id}/trips/{trip_id} . | 
| НЕ НАЙДЕНО | Поездка так и не была реализована. | 
| ДОСТУП ЗАПРЕЩЕН |  У приложения Consumer недостаточно прав. Эта ошибка возникает, когда:
  | 
| RESOURCE_EXHAUSTED | Квота ресурсов равна нулю, или скорость транспортного потока превышает ограничение скорости. | 
| НЕ ПОДТВЕРЖДЕНО | Запрос не прошёл аутентификацию из-за недействительного токена JWT. Эта ошибка возникает, если токен JWT подписан без идентификатора поездки или если срок действия токена JWT истёк. |