Primeiros passos com o SDK do driver para iOS

O SDK do Driver é uma biblioteca integrada ao app do motorista. Ele é responsável por atualizar o Fleet Engine com a localização do motorista, trajeto, distância restante e HEC. Ele também se integra ao SDK do Navigation, que fornece instruções de navegação guiada para o motorista.

Requisitos mínimos do sistema

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

    Este guia pressupõe que seu app já implementa o SDK do Navigation e que o back-end do Fleet Engine está configurado e disponível. No entanto, o código de exemplo fornece 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.

    Conseguir acesso

    Se você for cliente do Google Workspace, crie um grupo do Workspace, como google-maps-platform-sdk-users@workspacedomain.com, durante a integração, e forneça o nome ao Google. Esse é o método recomendado. Seu grupo do espaço de trabalho será adicionado a uma lista de permissões que concede acesso aos repositórios corretos do CocoaPods. Confirme se os e-mails do usuário e da conta de serviço que precisam de acesso estão incluídos nessa lista.

    Se sua organização não puder criar grupos do Workspace, envie ao Google uma lista de e-mails de usuários e contas de serviço que precisam de acesso a esses artefatos.

    Desenvolvimento local

    Para desenvolvimento local, é suficiente fazer login com o SDK do Cloud.

    gcloud

    gcloud auth login
    

    O e-mail usado para fazer login precisa ser de um participante do grupo do Workspace.

    Automação (sistemas de build ou integração contínua)

    Configure os hosts de automação de acordo com as práticas recomendadas:

    • Se o processo for executado em um ambiente do Google Cloud, use a detecção de credenciais automática.

    • Caso contrário, armazene o arquivo de chave da conta de serviço em um local seguro no sistema de arquivos do host e defina a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS corretamente.

    O e-mail da conta de serviço associado às credenciais precisa ser membro do grupo do espaço de trabalho.

    Configuração do projeto

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

    Usar o 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. shell 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 suas 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
      
    2. Salve o Podfile. Abra um terminal e acesse o diretório que contém o Podfile:

      cd <path-to-project>
      
    3. Execute o comando de instalação do pod. Isso instalará as APIs especificadas no Podfile com as respectivas dependências.

      pod install
      
    4. Feche o Xcode e clique duas vezes no arquivo .xcworkspace do seu projeto para iniciar o Xcode. A partir desse momento, use o arquivo .xcworkspace para abrir o projeto.

    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 do driver 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
      
    2. Salve o Podfile. Abra um terminal e acesse o diretório que contém o Podfile:

      cd <path-to-project>
      
    3. Execute o comando de instalação do pod. Isso instalará as APIs especificadas no Podfile com as respectivas dependências.

      pod install
      
    4. Feche o Xcode e clique duas vezes no arquivo .xcworkspace do seu projeto para iniciar o Xcode. A partir desse momento, use o arquivo .xcworkspace para abrir o projeto.

    Instalar o XCFramework

    Um XCFramework é um pacote binário usado para instalar o SDK do Driver. É possível usar esse pacote em várias plataformas, inclusive máquinas que usam o chipset M1. Este guia mostra como adicionar manualmente o XCFramework que contém o SDK do driver ao seu projeto e definir as configurações de compilação 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 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, se ainda não houver um.

    4. Arraste o arquivo gRPCCertificates.bundle transferido por download 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 arquivo GoogleRidesharingDriver.bundle transferido por download para o diretório de nível superior do seu projeto Xcode. Quando solicitado, selecione Copy items if needed.

    7. Selecione seu projeto no Navegador de projetos e escolha o destino de seu aplicativo.

    8. Abra a guia "Fases de build" e, em "Vincular binário a bibliotecas", adicione os seguintes frameworks e bibliotecas, 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 Configurações da versão. 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.

    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 do usuário da API Fleet Engine Deliveries para mais informações.

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

    #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 {
      if (!completion) {
        NSAssert(NO, @"%s encountered an unexpected nil completion.", __PRETTY_FUNCTION__);
        return;
      }
    
      // 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 vehicle token 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 DeliveryDriverAPI

    Para conseguir uma instância de GMTDDeliveryVehicleReporter, primeiro você precisa criar uma instância de GMTDDeliveryDriverAPI usando o providerID, o vehicleID, o driverContext e o accessTokenProvider. O providerID é igual ao ID do projeto do Google Cloud. E você pode acessar a instância GMTDDeliveryVehicleReporter diretamente na API do driver.

    O exemplo a seguir cria uma instância GMTDDeliveryDriverAPI:

    #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];
    
      GMTDDeliveryDriverAPI *deliveryDriverAPI = [[GMTDDeliveryDriverAPI alloc] initWithDriverContext:driverContext];
    }
    

    Como opção, detectar eventos do VehicleReporter

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

    É possível processar os seguintes eventos:

    • vehicleReporter:didSucceedVehicleUpdate

      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:didFailVehicleUpdate:withError

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

    O exemplo a seguir lida com esses eventos:

    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 IMPLEMENTED HAVE THE SAMPLE CODE UP TO THIS STEP.
      [ridesharingDriverAPI.vehicleReporter addListener:self];
    }
    
    - (void)vehicleReporter:(GMTDDeliveryVehicleReporter *)vehicleReporter didSucceedVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate {
      // Handle update succeeded.
    }
    
    - (void)vehicleReporter:(GMTDDeliveryVehicleReporter *)vehicleReporter didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate withError:(NSError *)error {
      // Handle update failed.
    }
    
    @end
    

    Ativar rastreamento de localização

    Para ativar o rastreamento de local, seu app pode definir locationTrackingEnabled como YES em GMTDDeliveryVehicleReporter. Depois, GMTDDeliveryVehicleReporter enviará automaticamente atualizações de localização. Quando GMSNavigator está no modo de navegação (quando um destino é definido pelo setDestinations) e locationTrackingEnabled está definido como YES, o GMTDDeliveryVehicleReporter também envia automaticamente atualizações de trajeto e HEC.

    O trajeto definido durante essas atualizações será o mesmo trajeto pelo qual o motorista está navegando durante a sessão de navegação. Para que o rastreamento de remessas funcione corretamente, o waypoint definido por -setDestinations:callback: precisa corresponder ao destino definido no back-end do Fleet Engine.

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

    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 IMPLEMENTED HAVE THE SAMPLE CODE UP TO THIS STEP.
      deliveryDriverAPI.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.

    Desativar atualizações de localização

    O app pode desativar as atualizações de local de um veículo. Por exemplo, quando o horário do motorista termina, o app pode definir locationTrackingEnabled como NO.

      _vehicleReporter.locationTrackingEnabled = NO
    

    Processar erros update_mask

    Quando o GMTDDeliveryVehicleReporter envia uma atualização do veículo, 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 lidar com 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