Primeiros passos com o SDK do driver para iOS

Você pode usar o SDK do Driver para oferecer navegação e rastreamento aprimorados ao seu aplicativo de viagem e andamento do pedido. O SDK do Driver fornece atualizações de local e tarefas de veículos ao mecanismo de frota da solução de viagens e entregas sob demanda.

O SDK do Driver mantém os serviços do Fleet Engine e seus serviços personalizados cientes da localização e do estado do veículo. Por exemplo, o veículo pode ser ONLINE ou OFFLINE, e a localização dele muda conforme a viagem progride.

Requisitos mínimos do sistema

  • O dispositivo móvel precisa ter o iOS 14 ou mais recente.
  • Xcode versão 14 ou mais recente.
  • Pré-requisitos

    Este guia pressupõe que seu app já implementa o SDK de navegação e que o back-end do Fleet Engine está configurado e disponível. No entanto, o código de exemplo apresenta uma amostra de como configurar o SDK do Navigation.

    Também é necessário ativar o SDK do Maps para iOS no projeto do Google Cloud e Gerar uma chave de API.

    Configuração do projeto

    É possível configurar o SDK do driver usando o CocoaPods.

    CocoaPods

    Para configurar o SDK do driver usando o CocoaPods, você precisa dos seguintes itens:

    • A ferramenta CocoaPods: para instalar esta ferramenta, abra o terminal e execute o comando a seguir.
    sudo gem install cocoapods
    

    Consulte o Guia de primeiros passos do CocoaPods para mais detalhes.

    1. Crie um Podfile para o SDK do driver e use-o para instalar a API e as dependências dela. Crie um arquivo chamado Podfile no diretório do projeto. Esse arquivo define as dependências do seu projeto. Edite o Podfile e adicione as dependências. Veja um exemplo que inclui as dependências:
    source "https://github.com/CocoaPods/Specs.git"
    
    target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
      pod 'GoogleRidesharingDriver'
    end
    

    Aqui está um exemplo que inclui os pods Alfa e Beta do SDK do Driver como dependências:

    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. Salve o Podfile. Abra um terminal e acesse o diretório que contém o Podfile:
    cd <path-to-project>
    
    1. Execute o comando de instalação do pod. Isso instalará as APIs especificadas no Podfile com as respectivas dependências.
    pod install
    
    1. Feche o Xcode e clique duas vezes no arquivo .xcworkspace do seu projeto para iniciar o Xcode. A partir desse momento, você precisará usar o arquivo .xcworkspace para abrir o projeto.

    Instalação manual

    Um XCFramework é um pacote binário usado para instalar o SDK do Driver. É possível usar esse pacote em várias plataformas, incluindo máquinas que usam o Apple Silicon. Este guia mostra como adicionar manualmente o XCFramework que contém o SDK do Driver ao seu projeto e definir as configurações de build no Xcode.

    Faça o download do binário e dos recursos do SDK:

    1. Descompacte os arquivos compactados para acessar o XCFramework e os recursos.

    2. Inicie o Xcode e abra um projeto existente ou crie um novo. Se você não tem experiência com o iOS, crie um novo projeto e selecione o modelo de app iOS.

    3. Crie um grupo do Frameworks no seu grupo de projeto, caso ainda não tenha um.

    4. Arraste o arquivo gRPCCertificates.bundle para o diretório de nível superior do seu projeto Xcode. Quando solicitado, selecione "Copiar itens", se necessário.

    5. Para instalar o SDK do driver, arraste o arquivo GoogleRidesharingDriver.xcframework para o projeto em Frameworks, bibliotecas e conteúdo incorporado. Quando solicitado, selecione Copiar itens, se necessário.

    6. Arraste o GoogleRidesharingDriver.bundle salvo para o diretório de nível superior do seu projeto Xcode. Quando solicitado, selecione Copy items if needed.

    7. Selecione o projeto no Navegador de projetos e escolha o alvo do aplicativo.

    8. Abra a guia "Fases de build" e, em "Vincular binário a bibliotecas", adicione os frameworks e bibliotecas a seguir, se ainda não estiverem presentes:

      • 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. Escolha seu projeto, em vez de um destino específico, e abra a guia Build Settings. Na seção Outras sinalizações do vinculador, adicione -ObjC para depuração e lançamento. Se essas configurações não estiverem visíveis, mude o filtro na barra "Build Settings" de Basic para All.

    Versões Alfa/Beta do SDK

    Para configurar as versões Alfa ou Beta do SDK do Driver para iOS, você precisa dos seguintes itens:

    • A ferramenta CocoaPods: para instalar esta ferramenta, abra o terminal e execute o comando a seguir.
    sudo gem install cocoapods
    

    Consulte o Guia de primeiros passos do CocoaPods para mais detalhes.

    • Sua conta de desenvolvimento na lista de acesso do Google. O repositório de pods das versões Alfa e Beta do SDK não é de fonte pública. Para acessá-las, entre em contato com o Engenheiro de clientes do Google. O engenheiro adiciona sua conta de desenvolvimento à lista de acesso e, em seguida, define um cookie para autenticação.

    Depois que o projeto estiver na lista de acesso, será possível acessar o pod.

    1. Crie um Podfile para o SDK de entrega para iOS e use-o para instalar a API e as dependências dela. Crie um arquivo chamado Podfile no diretório do projeto. Esse arquivo define as dependências do seu projeto. Edite o Podfile e adicione suas dependências. Veja um exemplo que inclui as dependências:
    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. Salve o Podfile. Abra um terminal e acesse o diretório que contém o Podfile:
    cd <path-to-project>
    
    1. Execute o comando de instalação do pod. Esse comando instala as APIs especificadas no Podfile com as respectivas dependências.
    pod install
    
    1. Feche o Xcode e clique duas vezes no arquivo .xcworkspace do seu projeto para iniciar o Xcode. A partir desse momento, você precisará usar o arquivo .xcworkspace para abrir o projeto.

    Implementar autorização e autenticação

    Quando o app do driver gera e envia atualizações para o back-end do Fleet Engine, as solicitações precisam incluir tokens de acesso válidos. Para autorizar e autenticar essas solicitações, o SDK do driver chama seu objeto em conformidade com o protocolo GMTDAuthorization. O objeto é responsável por fornecer o token de acesso necessário.

    Como desenvolvedor do app, você escolhe como os tokens são gerados. Sua implementação precisa oferecer a capacidade de fazer o seguinte:

    • Busque um token de acesso, possivelmente no formato JSON, de um servidor HTTPS.
    • analisar e armazenar em cache o token;
    • Atualizar o token quando ele expirar.

    Para detalhes sobre os tokens esperados pelo servidor do Fleet Engine, consulte Como criar um JSON Web Token (JWT) para autorização.

    O ID do provedor é o mesmo que o ID do projeto do Google Cloud. Consulte o Guia de início rápido do Fleet Engine para mais informações.

    O exemplo a seguir implementa um provedor de token de acesso:

    Swift

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

    Objective-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
    

    Criar uma instância da API RidesharingDriverAPI

    Para ter uma instância do GMTDVehicleReporter, primeiro você precisa criar uma instância do GMTDRidesharingDriverAPI usando o providerID, o ID do veículo, o driverContext e o accessTokenProvider. O providerID é igual ao ID do projeto do Google Cloud. E você pode acessar a instância GMTDVehicleReporter diretamente da API do driver.

    O exemplo a seguir cria uma instância GMTDRidesharingDriverAPI:

    Swift

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

    Objective-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];
    }
    

    Como opção, detectar eventos do VehicleReporter

    O GMTDVehicleReporter atualiza o veículo periodicamente quando locationTrackingEnabled é true. Para responder a essas atualizações periódicas, qualquer objeto pode se inscrever em eventos GMTDVehicleReporter seguindo o protocolo GMTDVehicleReporterListener.

    É possível processar os seguintes eventos:

    • vehicleReporter(_:didSucceed:)

      Informa ao app do motorista que os serviços de back-end receberam a atualização do local e do estado do veículo.

    • vehicleReporter(_:didFail:withError:)

      Informa ao listener que uma atualização de veículo falhou. Enquanto o rastreamento de localização estiver ativado, o GMTDVehicleReporter continuará enviando os dados mais recentes para o back-end do Fleet Engine.

    O exemplo a seguir lida com esses eventos:

    Swift

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

    Objective-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
    

    Adiciona GMTDVehicleReporter como um listener do GMSRoadSnappedLocationProvider

    Para fornecer atualizações de localização ao SDK do Driver, o GMTDVehicleReporter precisa ser definido como um listener do GMSRoadSnappedLocationProvider.

    Swift

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

    Objective-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
    

    Ativar rastreamento de localização

    Para ativar o rastreamento de localização, seu app pode definir locationTrackingEnabled como true em GMTDVehicleReporter. O GMTDVehicleReporter envia atualizações de local automaticamente. Depois que os serviços são correspondentes e atribuem o veículo a uma viagem, o GMTDVehicleReporter envia atualizações de trajeto automaticamente quando GMSNavigator está no modo de navegação (quando um destino é definido pelo setDestinations).

    O trajeto definido durante a atualização será o mesmo que o motorista estiver seguindo durante a sessão de navegação. Assim, para que o compartilhamento de jornada funcione corretamente, o waypoint definido por setDestinations precisa corresponder ao destino definido no back-end do Fleet Engine.

    Se locationTrackingEnabled for definido como true, as atualizações de viagens e veículos serão enviadas ao back-end do Fleet Engine em um intervalo regular com base no valor definido para locationUpdateInterval. Se locationTrackingEnabled for definido como false, as atualizações serão interrompidas e uma solicitação final de atualização do veículo será enviada ao back-end do Fleet Engine para definir o estado do veículo como GMTDVehicleState.offline. Consulte updateVehicleState para considerações especiais sobre como lidar com falhas quando locationTrackingEnabled está definido como false.

    O exemplo a seguir ativa o rastreamento de localização:

    Swift

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

    Objective-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
    

    Por padrão, o intervalo do relatório é de 10 segundos, mas pode ser alterado com locationUpdateInterval. O intervalo mínimo de atualização permitido é de cinco segundos. O intervalo máximo de atualização permitido é de 60 segundos. Atualizações mais frequentes podem resultar em solicitações mais lentas e erros.

    Atualizar o estado do veículo

    O exemplo abaixo mostra como definir o estado do veículo como ONLINE. Consulte updateVehicleState para ver mais detalhes.

    Swift

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

    Objective-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
    

    Um erro update_mask pode ocorrer quando a máscara está vazia e normalmente ocorre na primeira atualização após a inicialização. O exemplo a seguir mostra como processar esse erro:

    Swift

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

    Objective-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
    

    Desativar atualizações de localização e deixar o veículo off-line

    O app pode desativar as atualizações e deixar o veículo off-line. Por exemplo, quando o horário do motorista termina, o app pode definir locationTrackingEnabled como false. A desativação das atualizações também define o status do veículo como OFFLINE no back-end do Fleet Engine.

    Swift

    vehicleReporter.locationTrackingEnabled = false
    

    Objective-C

    _vehicleReporter.locationTrackingEnabled = NO;