Premiers pas avec le SDK Driver pour iOS

Le SDK Driver est une bibliothèque que vous intégrez à votre application de pilote. Elle est chargée de mettre à jour Fleet Engine avec la position du conducteur, son itinéraire, sa distance restante et son heure d'arrivée prévue. Il s'intègre également au SDK Navigation, qui fournit des instructions de navigation détaillées au conducteur.

Configuration système minimale requise

  • L'appareil mobile doit être équipé d'iOS 13 ou version ultérieure.
  • Xcode version 14 ou ultérieure.
  • Conditions préalables

    Ce guide suppose que votre application implémente déjà le SDK Navigation, et que le backend Fleet Engine est configuré et disponible. Cependant, l'exemple de code fournit un exemple de configuration du SDK Navigation.

    Vous devez également activer le SDK Maps pour iOS dans votre projet Google Cloud et obtenir une clé API.

    Obtenir l'accès

    Si vous êtes client Google Workspace, créez un groupe Workspace tel que google-maps-platform-sdk-users@workspacedomain.com lors de l'intégration et indiquez le nom à Google. Il s'agit de l'approche recommandée. Votre groupe d'espaces de travail est ensuite ajouté à une liste d'autorisation qui accorde l'accès aux dépôts CocoaPods appropriés. Vérifiez que les adresses e-mail des utilisateurs et des comptes de service qui nécessitent l'accès sont incluses dans cette liste.

    Si votre organisation ne peut pas créer de groupes Workspace, envoyez à Google la liste des adresses e-mail des utilisateurs et des comptes de service qui ont besoin d'accéder à ces artefacts.

    Développement local

    Pour le développement local, il suffit de se connecter à l'aide du SDK Cloud.

    gcloud

    gcloud auth login
    

    L'adresse e-mail utilisée pour se connecter doit être membre du groupe Workspace.

    Automatisation (systèmes de création ou intégration continue)

    Configurez les hôtes d'automatisation conformément aux bonnes pratiques:

    • Si votre processus s'exécute dans un environnement Google Cloud, utilisez la détection automatique des identifiants.

    • Sinon, stockez le fichier de clé du compte de service dans un emplacement sécurisé sur le système de fichiers de l'hôte et définissez la variable d'environnement GOOGLE_APPLICATION_CREDENTIALS de manière appropriée.

    L'adresse e-mail du compte de service associée aux identifiants doit être membre du groupe d'espaces de travail.

    Configuration du projet

    Vous pouvez configurer le pilote du SDK à l'aide de CocoaPods.

    Utiliser CocoaPods

    Pour configurer le SDK pilote à l'aide de CocoaPods, vous avez besoin des éléments suivants:

    • L'outil CocoaPods: pour installer cet outil, ouvrez le terminal et exécutez la commande suivante. shell sudo gem install cocoapodsPour en savoir plus, consultez le guide de démarrage de CocoaPods.
    1. Créez un fichier Podfile pour le SDK Driver et utilisez-le pour installer l'API et ses dépendances. Pour ce faire, créez un fichier nommé Podfile dans le répertoire de votre projet. Ce fichier définit les dépendances de votre projet. Modifiez le Podfile et ajoutez vos dépendances. Voici un exemple qui inclut les dépendances:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. Enregistrez le Podfile. Ouvrez un terminal et accédez au répertoire contenant le Podfile:

      cd <path-to-project>
      
    3. Exécutez la commande d'installation de pod. Les API spécifiées dans le Podfile seront installées, ainsi que les éventuelles dépendances.

      pod install
      
    4. Fermez Xcode, puis ouvrez (double-cliquez) le fichier .xcworkspace de votre projet pour lancer Xcode. Vous devrez désormais utiliser le fichier .xcworkspace pour ouvrir le projet.

    Versions alpha/bêta des SDK

    Pour configurer les versions alpha ou bêta du SDK Driver pour iOS, vous avez besoin des éléments suivants:

    • L'outil CocoaPods: pour installer cet outil, ouvrez le terminal et exécutez la commande suivante.

      sudo gem install cocoapods
      

      Pour en savoir plus, consultez le guide de démarrage de CocoaPods.

    • Votre compte de développement sur la liste d'accès Google. Le dépôt de pod des versions alpha et bêta du SDK n'est pas une source publique. Pour y accéder, contactez l'ingénieur client Google. L'ingénieur ajoute votre compte de développement à la liste d'accès, puis définit un cookie pour l'authentification.

    Une fois que votre projet figure sur la liste d'accès, vous pouvez accéder au pod.

    1. Créez un fichier Podfile pour le SDK Driver pour iOS, puis utilisez-le pour installer l'API et ses dépendances. Créez un fichier nommé Podfile dans le répertoire de votre projet. Ce fichier définit les dépendances de votre projet. Modifiez le Podfile et ajoutez vos dépendances. Voici un exemple qui inclut les dépendances:

      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. Enregistrez le Podfile. Ouvrez un terminal et accédez au répertoire contenant le Podfile:

      cd <path-to-project>
      
    3. Exécutez la commande d'installation de pod. Les API spécifiées dans le Podfile seront installées, ainsi que les éventuelles dépendances.

      pod install
      
    4. Fermez Xcode, puis ouvrez (double-cliquez) le fichier .xcworkspace de votre projet pour lancer Xcode. Vous devrez désormais utiliser le fichier .xcworkspace pour ouvrir le projet.

    Installer le XCFramework

    Un XCFramework est un package binaire que vous utilisez pour installer le SDK Driver. Vous pouvez utiliser ce package sur plusieurs plates-formes, y compris sur les machines utilisant le chipset M1. Ce guide explique comment ajouter manuellement à votre projet le XCFramework contenant le SDK pilote et configurer vos paramètres de compilation dans Xcode.

    1. Décompressez les fichiers sources que Google vous a envoyés.

    2. Lancez Xcode, puis ouvrez un projet existant ou créez-en un. Si vous débutez sur iOS, créez un projet et sélectionnez le modèle d'application iOS.

    3. S'il n'en existe pas déjà un, créez-le sous votre groupe de projet.

    4. Faites glisser le fichier gRPCCertificates.bundle inclus dans le répertoire Resources du fichier ZIP contenant le XCFramework vers le répertoire de premier niveau de votre projet Xcode. Lorsque vous y êtes invité, sélectionnez "Copy items if needed" (Copier les éléments si nécessaire).

    5. Pour installer le SDK Driver, faites glisser le fichier GoogleRidesharingDriver.xcframework dans votre projet sous Frameworks, Libraries, and Embedded Content. Lorsque vous y êtes invité, sélectionnez "Copy items if needed" (Copier les éléments si nécessaire).

    6. Effectuez un clic droit sur GoogleRidesharingDriver.xcframework dans votre projet, puis sélectionnez Show In Finder.

    7. Faites glisser GoogleRidesharingDriver.bundle du dossier ios-arm64_x86_64-simulator/GoogleRidesharingDriver.framework/Resources vers le répertoire de premier niveau de votre projet Xcode. Lorsque vous y êtes invité, vérifiez que Copy items if needed n'est pas sélectionné.

    8. Sélectionnez votre projet dans Project Navigator, puis choisissez la cible de votre application.

    9. Ouvrez l'onglet "Build Phases" (Phases de compilation), puis dans "Link Binary with libraries" (Associer le binaire avec les bibliothèques), ajoutez les frameworks et bibliothèques suivants si ils ne sont pas déjà présents:

      • 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
    10. Choisissez votre projet plutôt qu'une cible spécifique, puis ouvrez l'onglet Build Settings (Paramètres de compilation). Dans la section Other Linker Flags (Autres indicateurs Linker), ajoutez ‑ObjC pour le débogage et la version. Si ces paramètres ne sont pas visibles, remplacez le filtre Basic (De base) par All (Tous) dans la barre "Build Settings" (Paramètres de compilation).

    Implémenter l'autorisation et l'authentification

    Lorsque votre application de pilote génère et envoie des mises à jour au backend Fleet Engine, les requêtes doivent inclure des jetons d'accès valides. Pour autoriser et authentifier ces requêtes, le SDK Driver appelle votre objet conformément au protocole GMTDAuthorization. L'objet est chargé de fournir le jeton d'accès requis.

    En tant que développeur de l'application, vous choisissez la façon dont les jetons sont générés. Votre implémentation doit permettre d'effectuer les opérations suivantes:

    • Récupérer un jeton d'accès, éventuellement au format JSON, à partir d'un serveur HTTPS.
    • Analyser et mettre en cache le jeton.
    • Actualisez le jeton lorsqu'il expire.

    Pour en savoir plus sur les jetons attendus par le serveur Fleet Engine, consultez la page Créer un jeton Web JSON (JWT) pour l'autorisation.

    L'ID du fournisseur est identique à l'ID du projet Google Cloud. Consultez le guide de l'utilisateur de l'API Fleet Engine Deliveries pour en savoir plus.

    L'exemple suivant met en œuvre un fournisseur de jetons d'accès:

    #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
    

    Créer une instance DeliveryDriverAPI

    Pour obtenir une instance GMTDDeliveryVehicleReporter, vous devez d'abord créer une instance GMTDDeliveryDriverAPI à l'aide des informations providerID,vehicleID, driverContext et accessTokenProvider. L'ID du fournisseur est identique à l'ID du projet Google Cloud. De plus, vous pouvez accéder directement à l'instance GMTDDeliveryVehicleReporter à partir de l'API du pilote.

    L'exemple suivant crée une instance 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];
    }
    

    Écouter les événements VehicleReporter (facultatif)

    GMTDDeliveryVehicleReporter met régulièrement à jour le véhicule lorsque la valeur de locationTrackingEnabled est "OUI". Pour répondre à ces mises à jour périodiques, tout objet peut s'abonner aux événements GMTDDeliveryVehicleReporter en se conformant au protocole GMTDVehicleReporterListener.

    Vous pouvez gérer les événements suivants:

    • vehicleReporter:didSucceedVehicleUpdate

      Informe l'application Conducteur que les services de backend ont bien reçu la mise à jour de l'emplacement et de l'état du véhicule.

    • vehicleReporter:didFailVehicleUpdate:withError

      Informe l'écouteur qu'une mise à jour du véhicule a échoué. Tant que le suivi de la localisation est activé, GMTDDeliveryVehicleReporter continue d'envoyer les données les plus récentes au backend Fleet Engine.

    L'exemple suivant gère ces événements:

    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
    

    Activer le suivi de la position

    Pour activer le suivi de la position, votre application peut définir locationTrackingEnabled sur YES sur GMTDDeliveryVehicleReporter. Ensuite, GMTDDeliveryVehicleReporter enverra automatiquement les mises à jour de position. Lorsque GMSNavigator est en mode de navigation (lorsqu'une destination est définie via setDestinations) et que locationTrackingEnabled est défini sur YES, GMTDDeliveryVehicleReporter envoie automatiquement des mises à jour de l'itinéraire et de l'heure d'arrivée prévue.

    L'itinéraire défini lors de ces mises à jour sera le même que celui emprunté par le conducteur pendant la session de navigation. Ainsi, pour que le suivi des expéditions fonctionne correctement, le point de cheminement défini via -setDestinations:callback: doit correspondre à la destination définie dans le backend Fleet Engine.

    L'exemple suivant active le suivi de la position:

    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
    

    Par défaut, l'intervalle est de 10 secondes, mais vous pouvez le modifier avec locationUpdateInterval. L'intervalle minimal de mise à jour accepté est de 5 secondes. L'intervalle maximal de mises à jour accepté est de 60 secondes. Des mises à jour plus fréquentes peuvent ralentir les requêtes et les erreurs.

    Désactiver les mises à jour de la position géographique

    Votre application peut désactiver les mises à jour de la position d'un véhicule. Par exemple, à la fin de la période de travail d'un conducteur, votre application peut définir locationTrackingEnabled sur NO.

      _vehicleReporter.locationTrackingEnabled = NO
    

    Gérer les erreurs update_mask

    Lorsque GMTDDeliveryVehicleReporter envoie une mise à jour du véhicule, une erreur update_mask peut se produire lorsque le masque est vide. Elle se produit généralement lors de la première mise à jour après le démarrage. L'exemple suivant montre comment gérer cette erreur:

    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