Introduzione all'SDK Driver per iOS

L'SDK Driver è una libreria da integrare nell'app del conducente. È responsabile dell'aggiornamento di Fleet Engine con la posizione del conducente, il percorso, la distanza rimanente e l'orario di arrivo stimato. Inoltre, si integra con l'SDK di navigazione, che fornisce istruzioni di navigazione passo passo per il conducente.

Requisiti minimi di sistema

  • Sul dispositivo mobile deve essere installato iOS 14 o versioni successive.
  • Xcode 14 o versioni successive.
  • Prerequisiti

    Questa guida presuppone che la tua app implementi già l'SDK di navigazione e che il backend di Fleet Engine sia configurato e disponibile. Tuttavia, il codice di esempio fornisce un esempio di come configurare l'SDK di navigazione.

    Devi inoltre abilitare Maps SDK for iOS nel tuo progetto Google Cloud e ottenere una chiave API.

    Accesso

    Se sei un cliente Google Workspace, crea un gruppo Workspace, ad esempio google-maps-platform-sdk-users@workspacedomain.com, durante l'onboarding e fornisci il nome a Google. Questo è l'approccio consigliato. Il gruppo Workspace verrà quindi aggiunto a una lista consentita che concede l'accesso ai repository CocoaPods corretti. Verifica che gli indirizzi email degli utenti e degli account di servizio che richiedono l'accesso siano inclusi in questo elenco.

    Se la tua organizzazione non può creare gruppi Workspace, invia a Google un elenco di email di utenti e account di servizio che richiedono l'accesso a questi artefatti.

    Sviluppo locale

    Per lo sviluppo locale, è sufficiente accedere con Cloud SDK.

    gcloud

    gcloud auth login
    

    L'indirizzo email utilizzato per accedere deve far parte del gruppo Workspace.

    Automazione (creazione di sistemi o integrazione continua)

    Configura gli host di automazione in base alle best practice:

    • Se il processo viene eseguito all'interno di un ambiente Google Cloud, utilizza il rilevamento automatico delle credenziali.

    • In caso contrario, memorizza il file della chiave dell'account di servizio in una posizione sicura nel file system dell'host e imposta la variabile di ambiente GOOGLE_APPLICATION_CREDENTIALS in modo appropriato.

    L'indirizzo email dell'account di servizio associato alle credenziali deve fare parte del gruppo Workspace.

    Configurazione progetto

    Puoi configurare l'SDK Driver utilizzando CocoaPods.

    Utilizzare CocoaPods

    Per configurare l'SDK Driver utilizzando CocoaPods, devi disporre dei seguenti elementi:

    • Lo strumento CocoaPods: per installare questo strumento, apri il terminale ed esegui questo comando. shell sudo gem install cocoapods Per ulteriori dettagli, consulta la Guida introduttiva di CocoaPods.
    1. Crea un podfile per l'SDK Driver e utilizzalo per installare l'API e le sue dipendenze: crea un file denominato Podfile nella directory del progetto. Questo file definisce le dipendenze del progetto. Modifica il Podfile e aggiungi le dipendenze. Ecco un esempio che include le dipendenze:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. Salva il Podfile. Apri un terminale e vai alla directory contenente il pod:

      cd <path-to-project>
      
    3. Esegui il comando di installazione pod. In questo modo verranno installate le API specificate nel pod, insieme alle eventuali dipendenze.

      pod install
      
    4. Chiudi Xcode, quindi apri (doppio clic) il file .xcworkspace del tuo progetto per avviare Xcode. Da questo momento in poi, devi utilizzare il file .xcworkspace per aprire il progetto.

    Versioni SDK alpha/beta

    Per configurare le versioni alpha o beta dell'SDK Driver per iOS, sono necessari i seguenti elementi:

    • Lo strumento CocoaPods: per installare questo strumento, apri il terminale ed esegui questo comando.

      sudo gem install cocoapods
      

      Per ulteriori dettagli, consulta la Guida introduttiva di CocoaPods.

    • Il tuo account di sviluppo nell'elenco di accesso di Google. Il repository di pod delle versioni alpha e beta dell'SDK non è di origine pubblica. Per accedere a queste versioni, contatta il Customer Engineer di Google. Il tecnico aggiunge il tuo account di sviluppo all'elenco di accesso e poi imposta un cookie per l'autenticazione.

    Quando il tuo progetto è nell'elenco per gli accessi, puoi accedere al pod.

    1. Crea un podfile per l'SDK Driver per iOS e utilizzalo per installare l'API e le sue dipendenze: crea un file denominato Podfile nella directory del progetto. Questo file definisce le dipendenze del progetto. Modifica il Podfile e aggiungi le dipendenze. Ecco un esempio che include le dipendenze:

      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. Salva il Podfile. Apri un terminale e vai alla directory contenente il pod:

      cd <path-to-project>
      
    3. Esegui il comando di installazione pod. In questo modo verranno installate le API specificate nel pod, insieme alle eventuali dipendenze.

      pod install
      
    4. Chiudi Xcode, quindi apri (doppio clic) il file .xcworkspace del tuo progetto per avviare Xcode. Da questo momento in poi, devi utilizzare il file .xcworkspace per aprire il progetto.

    Installa XCFramework

    Un XCFramework è un pacchetto binario che utilizzi per installare l'SDK Driver. Puoi utilizzare questo pacchetto su più piattaforme, incluse le macchine che utilizzano il chipset M1. Questa guida mostra come aggiungere manualmente al progetto l'XCFramework contenente l'SDK Driver e come configurare le impostazioni di build in Xcode.

    Scarica il programma binario e le risorse dell'SDK:

    1. Apri i file compressi per accedere a XCFramework e alle risorse.

    2. Avvia Xcode e apri un progetto esistente o creane uno nuovo. Se è la prima volta che utilizzi iOS, crea un nuovo progetto e seleziona il modello di app per iOS.

    3. Se non ne esiste già uno, crea un gruppo di framework all'interno del gruppo di progetto.

    4. Trascina il file gRPCCertificates.bundle scaricato nella directory di primo livello del tuo progetto Xcode. Quando richiesto, seleziona Copia elementi se necessario.

    5. Per installare l'SDK Driver, trascina il file GoogleRidesharingDriver.xcframework nel progetto in Framework, librerie e contenuti incorporati. Quando richiesto, seleziona Copia elementi se necessario.

    6. Trascina l'elemento GoogleRidesharingDriver.bundle scaricato nella directory di primo livello del tuo progetto Xcode. Quando richiesto, seleziona Copy items if needed.

    7. Seleziona il progetto dal Navigatore progetti e scegli il target dell'applicazione.

    8. Apri la scheda Fasi di creazione e, in Collega binari alle librerie, aggiungi i seguenti framework e librerie, se non sono già presenti:

      • 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. Scegli il tuo progetto anziché un target specifico, quindi apri la scheda Impostazioni build. Nella sezione Altri flag linker, aggiungi ‑ObjC sia per il debug che per la release. Se queste impostazioni non sono visibili, nella barra delle impostazioni di build modifica il filtro da Di base a Tutti.

    Implementare autorizzazione e autenticazione

    Quando l'app Driver genera e invia aggiornamenti al backend Fleet Engine, le richieste devono includere token di accesso validi. Per autorizzare e autenticare queste richieste, l'SDK Driver chiama l'oggetto in modo conforme al protocollo GMTDAuthorization. L'oggetto è responsabile di fornire il token di accesso richiesto.

    In qualità di sviluppatore dell'app, sei tu a scegliere come generare i token. La tua implementazione dovrebbe consentirti di:

    • Recupera un token di accesso, possibilmente in formato JSON, da un server HTTPS.
    • Analizza e memorizza il token nella cache.
    • Aggiorna il token alla scadenza.

    Per i dettagli sui token previsti dal server Fleet Engine, consulta Creazione di un token JWT (JSON Web Token) per l'autorizzazione.

    L'ID provider è uguale all'ID progetto Google Cloud. Consulta la guida dell'utente dell'API Fleet Engine Deliveries per ulteriori informazioni.

    Nell'esempio seguente viene implementato un provider di token di accesso:

    #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
    

    Crea un'istanza DeliveryDriverAPI

    Per ottenere un'istanza GMTDDeliveryVehicleReporter, devi prima creare un'istanza GMTDDeliveryDriverAPI utilizzando providerID, vehicleID, driverContext e accessTokenProvider. Il providerID è uguale all'ID progetto Google Cloud. Puoi accedere all'istanza GMTDDeliveryVehicleReporter direttamente dall'API Driver.

    L'esempio seguente crea un'istanza 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];
    }
    

    (Facoltativo) Ascolta gli eventi VehicleReporter

    GMTDDeliveryVehicleReporter aggiorna periodicamente il veicolo quando locationTrackingEnabled è SÌ. Per rispondere a questi aggiornamenti periodici, qualsiasi oggetto può sottoscrivere eventi GMTDDeliveryVehicleReporter conformi al protocollo GMTDVehicleReporterListener.

    Puoi gestire i seguenti eventi:

    • vehicleReporter:didSucceedVehicleUpdate

      Comunica all'app Driver che i servizi di backend hanno ricevuto correttamente la posizione del veicolo e l'aggiornamento dello stato.

    • vehicleReporter:didFailVehicleUpdate:withError

      Comunica al listener che un aggiornamento del veicolo non è riuscito. Finché il monitoraggio della posizione è abilitato, GMTDDeliveryVehicleReporter continua a inviare i dati più recenti al backend di Fleet Engine.

    L'esempio seguente gestisce questi eventi:

    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
    

    Attiva il monitoraggio della posizione

    Per attivare il monitoraggio della posizione, la tua app può impostare locationTrackingEnabled su YES su GMTDDeliveryVehicleReporter. Dopodiché GMTDDeliveryVehicleReporter invierà automaticamente gli aggiornamenti sulla posizione. Quando GMSNavigator è in modalità di navigazione (quando una destinazione è impostata tramite setDestinations) e locationTrackingEnabled è impostato su YES, GMTDDeliveryVehicleReporter invierà automaticamente anche aggiornamenti sul percorso e sull'orario di arrivo stimato.

    Il percorso impostato durante questi aggiornamenti sarà lo stesso percorso dal conducente durante la sessione di navigazione. Di conseguenza, affinché il monitoraggio della spedizione funzioni correttamente, il waypoint impostato tramite -setDestinations:callback: deve corrispondere alla destinazione impostata nel backend di Fleet Engine.

    L'esempio seguente abilita il monitoraggio della posizione:

    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
    

    Per impostazione predefinita, l'intervallo di report è di 10 secondi, ma l'intervallo di report può essere modificato con locationUpdateInterval. L'intervallo di aggiornamento minimo supportato è di 5 secondi. L'intervallo di aggiornamento massimo supportato è di 60 secondi. Aggiornamenti più frequenti possono rallentare le richieste e gli errori.

    Disattivare gli aggiornamenti della posizione

    La tua app può disattivare gli aggiornamenti della posizione per un veicolo. Ad esempio, quando termina il turno di un conducente, la tua app può impostare locationTrackingEnabled su NO.

      _vehicleReporter.locationTrackingEnabled = NO
    

    Gestire gli errori update_mask

    Quando GMTDDeliveryVehicleReporter invia un aggiornamento del veicolo, può verificarsi un errore update_mask quando la maschera è vuota e in genere si verifica per il primo aggiornamento dopo l'avvio. Nell'esempio seguente viene illustrato come gestire questo errore:

    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