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

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

Driver SDK информирует службы Fleet Engine и ваши таможенные службы о местонахождении и состоянии транспортного средства. Например, транспортное средство может находиться в ONLINE или OFFLINE , а местоположение автомобиля меняется по ходу поездки.

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

  • Мобильное устройство должно работать под управлением iOS 14 или более поздней версии.
  • Xcode версии 14 или новее.
  • Предварительные условия

    В этом руководстве предполагается, что в вашем приложении уже реализован навигационный SDK , а серверная часть Fleet Engine настроена и доступна. Однако в примере кода представлен образец настройки Navigation SDK .

    Вам также необходимо включить Maps SDK для iOS в своем проекте Google Cloud и получить ключ API .

    Конфигурация проекта

    Вы можете настроить Driver SDK с помощью CocoaPods.

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

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

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

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

    1. Создайте подфайл для Driver SDK и используйте его для установки API и его зависимостей: Создайте файл с именем Podfile в каталоге вашего проекта. Этот файл определяет зависимости вашего проекта. Отредактируйте подфайл и добавьте свои зависимости. Вот пример, который включает зависимости:
    source "https://github.com/CocoaPods/Specs.git"
    
    target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
      pod 'GoogleRidesharingDriver'
    end
    

    Вот пример, который включает модули Alpha и Beta для Driver SDK в качестве зависимостей:

    source "https://cpdc-eap.googlesource.com/ridesharing-driver-sdk.git"
    source "https://github.com/CocoaPods/Specs.git"
    
    target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
      pod 'GoogleRidesharingDriver'
    end
    
    1. Сохраните подфайл. Откройте терминал и перейдите в каталог, содержащий подфайл:
    cd <path-to-project>
    
    1. Запустите команду установки модуля. При этом будут установлены API, указанные в подфайле, а также все зависимости, которые они могут иметь.
    pod install
    
    1. Закройте Xcode, а затем откройте (дважды щелкните) файл .xcworkspace вашего проекта, чтобы запустить Xcode. С этого момента вы должны использовать файл .xcworkspace для открытия проекта.

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

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

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

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

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

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

    4. Перетащите файл gRPCCertificates.bundle в каталог верхнего уровня вашего проекта Xcode. При появлении запроса выберите Копировать элементы, если необходимо.

    5. Чтобы установить Driver SDK, перетащите файл GoogleRidesharingDriver.xcframework в свой проект в разделе «Платформы, библиотеки и встроенный контент» . При появлении запроса выберите Копировать элементы, если необходимо.

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

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

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

      • Accelerate.framework
      • AudioToolbox.framework
      • AVFoundation.framework
      • CoreData.framework
      • CoreGraphics.framework
      • CoreLocation.framework
      • CoreTelephony.framework
      • CoreText.framework
      • GLKit.framework
      • ImageIO.framework
      • libc++.tbd
      • libxml2.tbd
      • libz.tbd
      • LocalAuthentication.framework
      • OpenGLES.framework
      • QuartzCore.framework
      • SystemConfiguration.framework
      • UIKit.framework
      • WebKit.framework
    9. Выберите свой проект, а не конкретную цель, и откройте вкладку «Настройки сборки» . В разделе «Другие флаги компоновщика» добавьте -ObjC как для отладки, так и для выпуска. Если эти настройки не отображаются, измените фильтр на панели «Настройки сборки» с «Базовый» на «Все» .

    Альфа/бета-версии SDK

    Чтобы настроить альфа- или бета-версию Driver SDK для iOS, вам потребуются следующие элементы:

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

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

    • Ваша учетная запись разработчика в списке доступа Google. Репозиторий модулей альфа- и бета-версий SDK не является общедоступным. Чтобы получить доступ к этим версиям, обратитесь к инженеру по работе с клиентами Google. Инженер добавляет вашу учетную запись разработчика в список доступа, а затем устанавливает файл cookie для аутентификации.

    После того как ваш проект будет в списке доступа, вы сможете получить доступ к модулю.

    1. Создайте подфайл для Delivery SDK для iOS и используйте его для установки API и его зависимостей: создайте файл с именем Podfile в каталоге вашего проекта. Этот файл определяет зависимости вашего проекта. Отредактируйте подфайл и добавьте свои зависимости. Вот пример, который включает зависимости:
    source "https://cpdc-eap.googlesource.com/ridesharing-driver-sdk.git"
    source "https://github.com/CocoaPods/Specs.git"
    
    target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
      pod 'GoogleRidesharingDriver'
    end
    
    1. Сохраните подфайл. Откройте терминал и перейдите в каталог, содержащий подфайл:
    cd <path-to-project>
    
    1. Запустите команду установки модуля. Эта команда устанавливает API, указанные в подфайле, а также любые зависимости, которые они могут иметь.
    pod install
    
    1. Закройте Xcode, а затем откройте (дважды щелкните) файл .xcworkspace вашего проекта, чтобы запустить Xcode. С этого момента вы должны использовать файл .xcworkspace для открытия проекта.

    Реализация авторизации и аутентификации

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

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

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

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

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

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

    Быстрый

    import GoogleRidesharingDriver
    
    private let providerURL = "INSERT_YOUR_TOKEN_PROVIDER_URL"
    
    class SampleAccessTokenProvider: NSObject, GMTDAuthorization {
      private struct AuthToken {
        // The cached vehicle token.
        let token: String
        // Keep track of when the token expires for caching.
        let expiration: TimeInterval
        // Keep track of the vehicle ID the cached token is for.
        let vehicleID: String
      }
    
      enum AccessTokenError: Error {
        case missingAuthorizationContext
        case missingData
      }
    
      private var authToken: AuthToken?
    
      func fetchToken(
        with authorizationContext: GMTDAuthorizationContext?,
        completion: @escaping GMTDAuthTokenFetchCompletionHandler
      ) {
        // Get the vehicle ID from the authorizationContext. This is set by the Driver SDK.
        guard let authorizationContext = authorizationContext else {
          completion(nil, AccessTokenError.missingAuthorizationContext)
          return
        }
        let vehicleID = authorizationContext.vehicleID
    
        // If appropriate, use the cached token.
        if let authToken = authToken,
          authToken.expiration > Date.now.timeIntervalSince1970 && authToken.vehicleID == vehicleID
        {
          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 vehicleTokenKey = "VEHICLE_TOKEN_KEY"
          let tokenExpirationKey = "TOKEN_EXPIRATION"
          guard let data = data,
            let fetchData = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
            let token = fetchData[vehicleTokenKey] as? String,
            let expiration = fetchData[tokenExpirationKey] as? Double
          else {
            completion(nil, AccessTokenError.missingData)
            return
          }
    
          strongSelf.authToken = AuthToken(
            token: token, expiration: expiration, vehicleID: vehicleID)
          completion(token, nil)
        }
        task.resume()
      }
    }
    

    Цель-C

    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    // SampleAccessTokenProvider.h
    @interface SampleAccessTokenProvider : NSObject<GMTDAuthorization>
    @end
    
    static NSString *const PROVIDER_URL = @"INSERT_YOUR_TOKEN_PROVIDER_URL";
    
    // SampleAccessTokenProvider.m
    @implementation SampleAccessTokenProvider{
      // The cached vehicle token.
      NSString *_cachedVehicleToken;
      // Keep track of the vehicle ID the cached token is for.
      NSString *_lastKnownVehicleID;
      // Keep track of when tokens expire for caching.
      NSTimeInterval _tokenExpiration;
    }
    
    -   (void)fetchTokenWithContext:(nullable GMTDAuthorizationContext *)authorizationContext
                       completion:(nonnull GMTDAuthTokenFetchCompletionHandler)completion {
      // Get the vehicle ID from the authorizationContext. This is set by the Driver SDK.
      NSString *vehicleID = authorizationContext.vehicleID;
      if (!vehicleID) {
        NSAssert(NO, @"Vehicle ID is missing from authorizationContext.");
        return;
      }
    
      // Clear cached vehicle token if vehicle ID has changed.
      if (![_lastKnownVehicleID isEqual:vehicleID]) {
        _tokenExpiration = 0.0;
        _cachedVehicleToken = nil;
      }
      _lastKnownVehicleID = vehicleID;
    
      // Clear cached vehicletoken if it has expired.
      if ([[NSDate date] timeIntervalSince1970] > _tokenExpiration) {
        _cachedVehicleToken = nil;
      }
    
      // If appropriate, use the cached token.
      if (_cachedVehicleToken) {
        completion(_cachedVehicleToken, 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 *vehicleTokenKey = @"VEHICLE_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->_cachedVehicleToken = JSONResponse[vehicleTokenKey];
              completion(JSONResponse[vehicleTokenKey], 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
    

    Создайте экземпляр RidesharingDriverAPI.

    Чтобы получить экземпляр GMTDVehicleReporter , сначала необходимо создать экземпляр GMTDRidesharingDriverAPI , используя идентификатор поставщика, идентификатор транспортного средства, driverContext и accessTokenProvider. Идентификатор поставщика совпадает с идентификатором проекта Google Cloud. И вы можете получить доступ к экземпляру GMTDVehicleReporter напрямую из API драйвера.

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

    Быстрый

    import GoogleRidesharingDriver
    
    private let providerID = "INSERT_YOUR_PROVIDER_ID"
    
    class SampleViewController: UIViewController {
      private let mapView: GMSMapView
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
        let vehicleID = "INSERT_CREATED_VEHICLE_ID"
        let accessTokenProvider = SampleAccessTokenProvider()
        let driverContext = GMTDDriverContext(
          accessTokenProvider: accessTokenProvider,
          providerID: providerID,
          vehicleID: vehicleID,
          navigator: mapView.navigator)
        let ridesharingDriverAPI = GMTDRidesharingDriverAPI(driverContext: driverContext)
      }
    }
    

    Цель-C

    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
      GMSMapView *_mapView;
    }
    
    -   (void)viewDidLoad {
      NSString *vehicleID = @"INSERT_CREATED_VEHICLE_ID";
      SampleAccessTokenProvider *accessTokenProvider =
                                    [[SampleAccessTokenProvider alloc] init];
      GMTDDriverContext *driverContext =
        [[GMTDDriverContext alloc] initWithAccessTokenProvider:accessTokenProvider
                                                    providerID:PROVIDER_ID
                                                     vehicleID:vehicleID
                                                     navigator:_mapView.navigator];
    
      GMTDRidesharingDriverAPI *ridesharingDriverAPI = [[GMTDRidesharingDriverAPI alloc] initWithDriverContext:driverContext];
    }
    

    При необходимости прослушивайте события VehicleReporter.

    GMTDVehicleReporter периодически обновляет транспортное средство, если locationTrackingEnabled имеет true . Чтобы реагировать на эти периодические обновления, любой объект может подписаться на события GMTDVehicleReporter , соответствуя протоколу GMTDVehicleReporterListener .

    Вы можете обрабатывать следующие события:

    • vehicleReporter(_:didSucceed:)

      Сообщает приложению для водителей, что серверные службы успешно получили обновление местоположения и состояния автомобиля.

    • vehicleReporter(_:didFail:withError:)

      Сообщает прослушивателю, что обновление транспортного средства не удалось. Пока отслеживание местоположения включено, GMTDVehicleReporter продолжает отправлять последние данные в серверную часть Fleet Engine.

    Следующий пример обрабатывает эти события:

    Быстрый

    import GoogleRidesharingDriver
    
    private let providerID = "INSERT_YOUR_PROVIDER_ID"
    
    class SampleViewController: UIViewController, GMTDVehicleReporterListener {
      private let mapView: GMSMapView
    
      override func viewDidLoad() {
        // Assumes you have implemented the sample code up to this step.
        ridesharingDriverAPI.vehicleReporter.add(self)
      }
    
      func vehicleReporter(_ vehicleReporter: GMTDVehicleReporter, didSucceed vehicleUpdate: GMTDVehicleUpdate) {
        // Handle update succeeded.
      }
    
      func vehicleReporter(_ vehicleReporter: GMTDVehicleReporter, didFail vehicleUpdate: GMTDVehicleUpdate, withError error: Error) {
        // Handle update failed.
      }
    }
    

    Цель-C

    /*
    
        *   SampleViewController.h
     */
    @interface SampleViewController : UIViewController<GMTDVehicleReporterListener>
    @end
    
    /*
    
        *   SampleViewController.m
     */
    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
      GMSMapView *_mapView;
    }
    
    -   (void)viewDidLoad {
      // Assumes you have implemented the sample code up to this step.
      [ridesharingDriverAPI.vehicleReporter addListener:self];
    }
    
    -   (void)vehicleReporter:(GMTDVehicleReporter *)vehicleReporter didSucceedVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate {
      // Handle update succeeded.
    }
    
    -   (void)vehicleReporter:(GMTDVehicleReporter *)vehicleReporter didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate withError:(NSError *)error {
      // Handle update failed.
    }
    
    @end
    

    Добавьте GMTDVehicleReporter в качестве прослушивателя GMSRoadSnappedLocationProvider.

    Чтобы предоставлять обновления местоположения в Driver SDK, GMTDVehicleReporter необходимо настроить в качестве прослушивателя GMSRoadSnappedLocationProvider .

    Быстрый

    import GoogleRidesharingDriver
    
    private let providerID = "INSERT_YOUR_PROVIDER_ID"
    
    class SampleViewController: UIViewController, GMTDVehicleReporterListener {
      private let mapView: GMSMapView
    
      override func viewDidLoad() {
        // Assumes you have implemented the sample code up to this step.
        if let roadSnappedLocationProvider = mapView.roadSnappedLocationProvider {
          roadSnappedLocationProvider.add(ridesharingDriverAPI.vehicleReporter)
          roadSnappedLocationProvider.startUpdatingLocation()
        }
      }
    }
    

    Цель-C

    /*
    
        *   SampleViewController.h
     */
    @interface SampleViewController : UIViewController<GMTDVehicleReporterListener>
    @end
    
    /*
    
        *   SampleViewController.m
     */
    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
      GMSMapView *_mapView;
    }
    
    -   (void)viewDidLoad {
      // Assumes you have implemented the sample code up to this step.
      [_mapView.roadSnappedLocationProvider addListener:ridesharingDriverAPI.vehicleReporter];
      [_mapView.roadSnappedLocationProvider startUpdatingLocation];
    }
    
    @end
    

    Включить отслеживание местоположения

    Чтобы включить отслеживание местоположения, ваше приложение может установить для locationTrackingEnabled значение true в GMTDVehicleReporter . GMTDVehicleReporter автоматически отправляет обновления местоположения. После того, как службы сопоставят и назначат транспортное средство для поездки, GMTDVehicleReporter автоматически отправляет обновления маршрута, когда GMSNavigator находится в режиме навигации (когда пункт назначения задан с помощью setDestinations ).

    Маршрут, установленный во время обновления поездки, будет тем же маршрутом, по которому водитель движется во время сеанса навигации. Таким образом, чтобы совместное использование поездок работало правильно, путевая точка, установленная через setDestinations , должна совпадать с пунктом назначения, установленным в серверной части Fleet Engine.

    Если для locationTrackingEnabled установлено значение true , обновления о поездках и транспортных средствах отправляются на серверную часть Fleet Engine через регулярные интервалы в зависимости от значения, установленного для locationUpdateInterval . Если для locationTrackingEnabled установлено значение false , обновления прекращаются, и на серверную часть Fleet Engine отправляется окончательный запрос на обновление транспортного средства, чтобы установить состояние транспортного средства на GMTDVehicleState.offline . См. updateVehicleState для получения особых рекомендаций по обработке сбоев, когда locationTrackingEnabled установлено значение false .

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

    Быстрый

    import GoogleRidesharingDriver
    
    private let providerID = "INSERT_YOUR_PROVIDER_ID"
    
    class SampleViewController: UIViewController, GMTDVehicleReporterListener {
      private let mapView: GMSMapView
    
      override func viewDidLoad() {
        // Assumes you have implemented the sample code up to this step.
        ridesharingDriverAPI.vehicleReporter.locationTrackingEnabled = true
      }
    }
    

    Цель-C

    /*
      * SampleViewController.m
     */
    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
      GMSMapView *_mapView;
    }
    
    -   (void)viewDidLoad {
      // Assumes you have implemented the sample code up to this step.
      ridesharingDriverAPI.vehicleReporter.locationTrackingEnabled = YES;
    }
    
    @end
    

    По умолчанию интервал отчетов составляет 10 секунд, но интервал отчетов можно изменить с помощью locationUpdateInterval . Минимальный поддерживаемый интервал обновления составляет 5 секунд. Максимальный поддерживаемый интервал обновления составляет 60 секунд. Более частые обновления могут привести к замедлению запросов и ошибкам.

    Обновить состояние автомобиля

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

    Быстрый

    import GoogleRidesharingDriver
    
    private let providerID = "INSERT_YOUR_PROVIDER_ID"
    
    class SampleViewController: UIViewController, GMTDVehicleReporterListener {
      private let mapView: GMSMapView
    
      override func viewDidLoad() {
        // Assumes you have implemented the sample code up to this step.
        ridesharingDriverAPI.vehicleReporter.update(.online)
      }
    }
    

    Цель-C

    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
      GMSMapView *_mapView;
    }
    
    -   (void)viewDidLoad {
      // Assumes you have implemented the sample code up to this step.
      [ridesharingDriverAPI.vehicleReporter
                                       updateVehicleState:GMTDVehicleStateOnline];
    }
    
    @end
    

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

    Быстрый

    import GoogleRidesharingDriver
    
    class VehicleReporterListener: NSObject, GMTDVehicleReporterListener {
      func vehicleReporter(
        _ vehicleReporter: GMTDVehicleReporter,
        didFail vehicleUpdate: GMTDVehicleUpdate,
        withError error: Error
      ) {
        let fullError = error as NSError
        if let innerError = fullError.userInfo[NSUnderlyingErrorKey] as? NSError {
          let innerFullError = innerError as NSError
          if innerFullError.localizedDescription.contains("update_mask cannot be empty") {
            emptyMaskUpdates += 1
            return
          }
        }
        failedUpdates += 1
      }
    
      override init() {
        emptyMaskUpdates = 0
        failedUpdates = 0
      }
    }
    
    

    Цель-C

    #import "VehicleReporterListener.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    @implementation VehicleReporterListener {
      NSInteger emptyMaskUpdates = 0;
      NSInteger failedUpdates = 0;
    }
    
    -   (void)vehicleReporter:(GMTDVehicleReporter *)vehicleReporter
       didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate
                  withError:(NSError *)error {
      for (NSError *underlyingError in error.underlyingErrors) {
        if ([underlyingError.localizedDescription containsString:@"update_mask cannot be empty"]) {
          emptyMaskUpdates += 1;
          return;
        }
      }
      failedUpdates += 1
    }
    
    @end
    

    Отключите обновление местоположения и отключите автомобиль от сети.

    Ваше приложение может отключить обновления и отключить автомобиль. Например, когда смена водителя заканчивается, ваше приложение может установить для locationTrackingEnabled значение false . Отключение обновлений также переводит статус автомобиля в OFFLINE на серверной части Fleet Engine.

    Быстрый

    vehicleReporter.locationTrackingEnabled = false
    

    Цель-C

    _vehicleReporter.locationTrackingEnabled = NO;