Vous pouvez utiliser le SDK Driver pour améliorer la navigation et le suivi dans votre application "Trajet et progression de la commande". Le SDK Driver fournit des informations sur l'emplacement des véhicules et les tâches au moteur du parc de solutions On-demand Rides and Deliveries.
Le SDK Driver informe les services Fleet Engine et vos services personnalisés de l'emplacement et de l'état du véhicule. Par exemple, le véhicule peut être ONLINE
ou OFFLINE
, et son emplacement change au fur et à mesure du trajet.
Configuration système minimale requise
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. Toutefois, l'exemple de code fournit un exemple de configuration du SDK de navigation.
Vous devez également activer le SDK Maps pour iOS dans votre projet Google Cloud et obtenir une clé API.
Configuration du projet
Vous pouvez configurer le SDK pilote à l'aide de CocoaPods.
Utiliser CocoaPods
Pour configurer le SDK Driver à 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 cocoapods
Pour en savoir plus, consultez le guide de démarrage de CocoaPods.
Créez un fichier Podfile pour le SDK Driver et 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://github.com/CocoaPods/Specs.git" target 'YOUR_APPLICATION_TARGET_NAME_HERE' do pod 'GoogleRidesharingDriver' end
Voici un exemple qui inclut les pods alpha et bêta du SDK du pilote en tant que 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
Enregistrez le fichier Podfile. Ouvrez un terminal et accédez au répertoire contenant le fichier Podfile:
cd <path-to-project>
Exécutez la commande d'installation du pod. Les API spécifiées dans le Podfile seront installées, ainsi que toutes les dépendances dont elles peuvent disposer.
pod install
Fermez Xcode, puis ouvrez (double-cliquez) le fichier .xcworkspace de votre projet pour lancer Xcode. À partir de ce moment, vous devrez 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 pods des versions alpha et bêta du SDK n'est pas une source publique. Pour accéder à ces versions, 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.
Créez un fichier Podfile pour le SDK Delivery pour iOS et utilisez-le afin d'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
Enregistrez le fichier Podfile. Ouvrez un terminal et accédez au répertoire contenant le fichier Podfile:
cd <path-to-project>
Exécutez la commande d'installation du pod. Cette commande installe les API spécifiées dans le Podfile, ainsi que toutes les dépendances dont elles peuvent disposer.
pod install
Fermez Xcode, puis ouvrez (double-cliquez) le fichier .xcworkspace de votre projet pour lancer Xcode. À partir de ce moment, vous devrez utiliser le fichier .xcworkspace pour ouvrir le projet.
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 d'applications, vous choisissez comment les jetons sont générés. Votre implémentation doit permettre d'effectuer les opérations suivantes:
- Extrayez 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. Pour en savoir plus, consultez le guide de démarrage rapide de Parc Engine.
L'exemple suivant met en œuvre un fournisseur de jetons d'accès:
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
Créer une instance RidesharingDriverAPI
Pour obtenir une instance GMTDVehicleReporter
, vous devez d'abord créer une instance GMTDRidesharingDriverAPI
à l'aide des informations providerID,vehicleID, driverContext et accessTokenProvider. L'ID du fournisseur est identique à l'ID du projet Google Cloud. Vous pouvez également accéder directement à l'instance GMTDVehicleReporter
à partir de l'API du pilote.
L'exemple suivant crée une instance 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];
}
Écouter les événements VehicleReporter
GMTDVehicleReporter
met régulièrement à jour le véhicule lorsque locationTrackingEnabled
est défini sur true
. Pour répondre à ces mises à jour périodiques, tout objet peut s'abonner aux événements GMTDVehicleReporter
en se conformant au protocole GMTDVehicleReporterListener
.
Vous pouvez gérer les événements suivants:
vehicleReporter(_:didSucceed:)
Informe l'application du conducteur que les services de backend ont bien reçu la mise à jour de l'emplacement et de l'état du véhicule.
vehicleReporter(_:didFail:withError:)
Informe l'écouteur qu'une mise à jour du véhicule a échoué. Tant que le suivi de la position est activé,
GMTDVehicleReporter
continue d'envoyer les données les plus récentes au backend de Fleet Engine.
L'exemple suivant gère ces événements:
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
Ajout de GMTDVehicleReporter en tant qu'écouteur à GMSRoadSnappedLocationProvider.
Pour fournir des mises à jour de position au SDK Driver, GMTDVehicleReporter
doit être défini en tant qu'écouteur de 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
Activer le suivi de la position
Pour activer le suivi de la position, votre application peut définir locationTrackingEnabled
sur true
sur GMTDVehicleReporter
. GMTDVehicleReporter
envoie automatiquement des mises à jour de la position géographique.
Une fois que les services correspondent et ont attribué le véhicule à un trajet, GMTDVehicleReporter
envoie automatiquement des mises à jour de l'itinéraire lorsque GMSNavigator
est en mode de navigation (lorsqu'une destination est définie via setDestinations
).
L'itinéraire défini lors de la mise à jour du trajet correspond à l'itinéraire que le conducteur emprunte pendant la session de navigation.
Ainsi, pour que le partage de trajets fonctionne correctement, le point de cheminement défini via setDestinations
doit correspondre à la destination définie dans le backend Fleet Engine.
Si locationTrackingEnabled
est défini sur true
, les mises à jour des trajets et des véhicules sont envoyées au backend Fleet Engine à intervalle régulier en fonction de la valeur définie pour locationUpdateInterval
. Si locationTrackingEnabled
est défini sur false
, les mises à jour s'arrêtent et une requête finale de mise à jour du véhicule est envoyée au backend Fleet Engine pour définir l'état du véhicule sur GMTDVehicleState.offline
.
Consultez la section updateVehicleState
pour en savoir plus sur la gestion des échecs lorsque locationTrackingEnabled
est défini sur false
.
L'exemple suivant active le suivi de la position:
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
Par défaut, l'intervalle de reporting est de 10 secondes, mais vous pouvez le modifier à l'aide de locationUpdateInterval
. L'intervalle de mise à jour minimal accepté est de 5 secondes. L'intervalle maximal de mise à jour accepté est de 60 secondes. Des mises à jour plus fréquentes peuvent ralentir les requêtes et les erreurs.
Modifier l'état du véhicule
L'exemple suivant montre comment définir l'état du véhicule sur ONLINE
.
Pour en savoir plus, consultez la page updateVehicleState
.
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
Une erreur update_mask
peut se produire lorsque le masque est vide et 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
Désactiver les mises à jour de la position et mettre le véhicule hors connexion
Votre application peut désactiver les mises à jour et mettre le véhicule hors connexion. Par exemple, à la fin de la période de travail d'un conducteur, votre application peut définir locationTrackingEnabled
sur false
. La désactivation des mises à jour définit également l'état du véhicule sur OFFLINE
sur le backend Fleet Engine.
Swift
vehicleReporter.locationTrackingEnabled = false
Objective-C
_vehicleReporter.locationTrackingEnabled = NO;