Начало работы с Consumer SDK для iOS

Вы можете использовать Consumer SDK для создания и запуска базового потребительского приложения, интегрированного с серверными службами решения On-demand Rides and Delivery Solution. Вы можете создать приложение «Прогресс поездки и заказа», которое может отображать активную поездку, реагировать на обновления поездки и обрабатывать ошибки поездки.

Поскольку Consumer SDK имеет модульную архитектуру, вы можете использовать части API, которые хотите использовать для своего конкретного приложения, и интегрировать их со своими собственными API, серверными службами, предоставляемыми Fleet Engine, и дополнительными API платформы Google Maps. .

Минимальные системные требования

  • Мобильное устройство должно работать под управлением iOS 14 или более поздней версии.
  • Xcode версии 15 или новее.
  • Конфигурация проекта

    Менеджер пакетов Swift

    Consumer SDK можно установить через Swift Package Manager . Чтобы добавить SDK, убедитесь, что вы удалили все существующие зависимости Consumer SDK.

    Чтобы добавить SDK в новый или существующий проект, выполните следующие действия:

    1. Откройте project или workspace Xcode, затем выберите «Файл» > «Добавить зависимости пакета» .
    2. Введите https://github.com/googlemaps/ios-consumer-sdk в качестве URL-адреса, нажмите Enter , чтобы получить пакет, и нажмите «Добавить пакет».
    3. Чтобы установить конкретную version , установите в поле «Правило зависимости» один из вариантов, зависящих от версии. Для новых проектов рекомендуем указывать последнюю версию и использовать опцию «Точная версия». После завершения нажмите «Добавить пакет».
    4. В окне «Выбор пакетных продуктов» убедитесь, что GoogleRidesharingConsumer будет добавлен к назначенной вами main цели. После завершения нажмите «Добавить пакет».
    5. Чтобы проверить установку, перейдите на панель General » целевой системы. В разделе «Платформы», «Библиотеки» и «Встроенный контент» вы должны увидеть установленные пакеты. Вы также можете просмотреть раздел «Зависимости пакетов» в «Навигаторе проекта», чтобы проверить пакет и его версию.

    Чтобы обновить package для существующего проекта, выполните следующие действия:

    1. В Xcode перейдите в «Файл» > «Пакеты» > «Обновить до последних версий пакетов».
    2. Чтобы проверить установку, перейдите в раздел «Зависимости пакетов» в «Навигаторе проекта» , чтобы проверить пакет и его версию.

    Чтобы удалить существующие зависимости Consumer SDK, добавленные с помощью CocoaPods , выполните следующие действия:

    1. Закройте рабочую область Xcode. Откройте терминал и выполните следующую команду:
      sudo gem install cocoapods-deintegrate cocoapods-clean 
      pod deintegrate 
      pod cache clean --all
    2. Удалите Podfile , Podfile.resolved и workspace Xcode, если вы не используете их ни для чего, кроме CocoaPods.

    Чтобы удалить существующий Consumer SDK, установленный вручную, выполните следующие действия:

    1. В настройках конфигурации проекта Xcode найдите Frameworks, Libraries и Embedded Content . Используйте знак минус (-) , чтобы удалить следующую структуру:

      • GoogleRidesharingConsumer.xcframework
    2. Из каталога верхнего уровня вашего проекта Xcode удалите пакет GoogleRidesharingConsumer .

    Какао-стручки

    Чтобы настроить Consumer SDK с использованием CocoaPods, вам потребуются следующие элементы:

    • Инструмент CocoaPods: Чтобы установить этот инструмент, откройте Терминал и выполните следующую команду.

      sudo gem install cocoapods
      

    Дополнительные сведения см. в руководстве по началу работы с CocoaPods .

    1. Создайте подфайл для Consumer SDK и используйте его для установки API и его зависимостей. Сначала создайте файл с именем Podfile в каталоге вашего проекта. Этот файл определяет зависимости вашего проекта. Затем отредактируйте подфайл и добавьте свои зависимости. Вот пример, который включает зависимости:

        source "https://github.com/CocoaPods/Specs.git"
      
        target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
          pod 'GoogleRidesharingConsumer'
        end
      
    2. Сохраните подфайл. Откройте терминал и перейдите в каталог, содержащий подфайл:

      cd <path-to-project>
      
    3. Запустите команду установки модуля. При этом будут установлены API, указанные в подфайле, а также все зависимости, которые они могут иметь.

      pod install
      
    4. Закройте Xcode, а затем откройте (дважды щелкните) файл .xcworkspace вашего проекта, чтобы запустить Xcode. Чтобы открыть проект позже, используйте файл .xcworkspace.

    Ручная установка

    XCFramework — это двоичный пакет, который вы используете для установки Consumer SDK. Вы можете использовать этот пакет на нескольких платформах, включая машины, использующие набор микросхем M1. В этом руководстве показано, как вручную добавить XCFramework, содержащий Consumer SDK, в ваш проект и настроить параметры сборки в Xcode.

    Загрузите двоичный файл SDK и ресурсы:

    1. Распакуйте заархивированные файлы, чтобы получить доступ к XCFramework и ресурсам.

    2. Запустите Xcode и либо откройте существующий проект, либо создайте новый проект. Если вы новичок в iOS, создайте новый проект и выберите шаблон приложения iOS.

    3. Создайте группу Frameworks в группе проекта, если она еще не существует.

    4. Чтобы установить Consumer SDK, перетащите файл GoogleRidesharingConsumer.xcframework в свой проект в разделе Frameworks, Libraries и Embedded Content . При появлении запроса выберите Копировать элементы, если необходимо.

    5. Перетащите загруженный файл GoogleRidesharingConsumer.bundle в каталог верхнего уровня вашего проекта Xcode. При появлении запроса выберите Copy items if needed .

    6. Выберите свой проект в Навигаторе проектов и выберите цель своего приложения.

    7. Откройте вкладку «Фазы сборки» и в разделе «Связывание двоичных файлов с библиотеками» добавьте следующие платформы и библиотеки, если они еще не присутствуют:

      • 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. Выберите свой проект, а не конкретную цель, и откройте вкладку «Настройки сборки» . В разделе «Другие флаги компоновщика» добавьте -ObjC как для отладки, так и для выпуска. Если эти настройки не отображаются, измените фильтр на панели «Настройки сборки» с «Базовый» на «Все» .

    Добавить файл манифеста конфиденциальности Apple

    1. Загрузите пакет манифеста конфиденциальности для Consumer SDK для iOS: GoogleRidesharingConsumerPrivacy .
    2. Извлеките файл, чтобы получить доступ к GoogleRidesharingConsumerPrivacy.bundle .
    3. Скопируйте GoogleRidesharingConsumerPrivacy.bundle в каталог верхнего уровня вашего проекта Xcode.

    Интеграция приложений

    Предоставьте токен аутентификации

    Когда ваше потребительское приложение запрашивает обновления о поездках от Fleet Engine, запросы должны включать действительные токены доступа. Чтобы авторизовать и аутентифицировать эти запросы, Consumer SDK вызывает ваш объект в соответствии с протоколом GMTCAuthorization . Объект отвечает за предоставление необходимого токена доступа.

    Как разработчик приложения вы выбираете, как генерируются токены. Ваша реализация должна обеспечивать возможность делать следующее:

    • Получите токен доступа, возможно, в формате JSON, с HTTPS-сервера.
    • Разберите и кэшируйте токен.
    • Обновите токен по истечении срока его действия.

    Подробную информацию о токенах, ожидаемых сервером Fleet Engine, см. в разделе Создание веб-токена JSON (JWT) для авторизации .

    Идентификатор провайдера совпадает с идентификатором проекта Google Cloud. Для получения дополнительной информации см. Начало работы с Fleet Engine .

    В следующем примере реализуется поставщик токенов доступа:

    Быстрый

    /*
    
        *   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()
      }
    }
    

    Цель-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
    

    Инициализация приложения

    Быстрый

    /*
    
        *   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
      }
    }
    

    Цель-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 .

    Быстрый

    /*
    
        *   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!)
        ...
      }
    

    Цель-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
    

    Обработка событий просмотра карты

    В следующем примере показано, как реализовать делегат для обработки событий состояния клиента.

    Быстрый

    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.
    }
    

    Цель-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 , чтобы напрямую начать совместное путешествие.

    Быстрый

    /*
    
        *   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()
    }
    

    Цель-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)
    }
    

    Цель-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)
    }
    

    Цель-C

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

    В следующем примере показано, как отменить регистрацию обратного вызова tripModel .

    Быстрый

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

    Цель-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.
    }
    

    Цель-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:) . Fleet Engine выдал сообщение об ошибке, соответствующее стандарту Google Cloud Error. Подробное определение сообщения об ошибке и все коды ошибок см. в документации Google Cloud Errors .

    В частности, для мониторинга поездок требуется предоставить действительный токен аутентификации. 401 UNAUTHENTICATED будет возникать, если нет действительных учетных данных для аутентификации, например, срок действия токена истек. 403 PERMISSION_DENIED будет возникать, если у вызывающей стороны нет разрешения на вызов определенного API (например, пользователь с ролью потребителя пытается вызвать updateTrip) или в запросе нет допустимого транспортного средства/trip_id в токене JWT.

    Дополнительные сведения см. в разделе Обработка ошибок Consumer SDK .

    Настройка пользовательского интерфейса

    Получение и установка пользовательских параметров пользовательского интерфейса полилинии

    В следующем примере показано, как задать пользовательские параметры пользовательского интерфейса для полилиний.

    Быстрый

    /** 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)
    }
    

    Цель-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];
    }
    

    Получение и установка параметров пользовательского интерфейса маркера

    В следующем примере показано, как установить пользовательские параметры пользовательского интерфейса для маркеров.

    Быстрый

    /** 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)
    }
    

    Цель-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 для iOS центрирует камеру по местоположению устройства.

    Если есть активный сеанс обмена информацией о путешествиях, вы можете отцентрировать камеру, чтобы сфокусироваться на путешествии, а не только на местоположении устройства.

    Consumer SDK предоставляет функцию автоматической камеры, которая включена по умолчанию. Камера масштабируется, чтобы сфокусироваться на маршруте совместного путешествия и следующей путевой точке.

    АвтоКамера

    Если вам требуется больший контроль над поведением камеры, вы можете отключить или включить функцию автоматической камеры с помощью свойства isAllowCameraAutoUpdate .

    Дополнительные сведения о настройке камеры см. в разделе Maps SDK для iOS. Перемещение камеры .