Puoi utilizzare l'SDK Driver per fornire funzionalità avanzate di navigazione e monitoraggio nella tua applicazione di avanzamento del viaggio e dell'ordine. L'SDK Driver fornisce aggiornamenti della posizione del veicolo e delle attività al Fleet Engine della soluzione On-demand Rides and Deliveries.
L'SDK Driver mantiene i servizi Fleet Engine e i tuoi servizi personalizzati consapevoli della posizione e dello stato del veicolo. Ad esempio, il veicolo può essere ONLINE
o OFFLINE
e la posizione del veicolo cambia man mano che il percorso procede.
Requisiti minimi di sistema
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.
Configurazione progetto
Puoi configurare l'SDK Driver utilizzando CocoaPods.
Utilizzare CocoaPods
Per configurare l'SDK Driver utilizzando CocoaPods, sono necessari i seguenti elementi:
- 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 a CocoaPods.
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
Ecco un esempio che include come dipendenze i pod alpha e beta dell'SDK Driver:
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
Salva il podfile. Apri un terminale e vai alla directory contenente il podfile:
cd <path-to-project>
Esegui il comando di installazione pod. Questa operazione installerà le API specificate nel podfile, insieme alle eventuali dipendenze.
pod install
Chiudi Xcode, quindi apri (doppio clic) il file .xcworkspace del 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:
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 per gli accessi 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 degli accessi, quindi imposta un cookie per l'autenticazione.
Una volta che il tuo progetto è nell'elenco degli accessi, puoi accedere al pod.
Crea un podfile per l'SDK Delivery 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
Salva il podfile. Apri un terminale e vai alla directory contenente il podfile:
cd <path-to-project>
Esegui il comando di installazione pod. Questo comando installa le API specificate nel podfile, insieme alle eventuali dipendenze.
pod install
Chiudi Xcode, quindi apri (doppio clic) il file .xcworkspace del progetto per avviare Xcode. Da questo momento in poi, devi utilizzare il file .xcworkspace per aprire il progetto.
Implementare autorizzazione e autenticazione
Quando l'app Driver genera e invia aggiornamenti al backend di Fleet Engine, le richieste devono includere token di accesso validi. Per autorizzare e autenticare queste richieste, l'SDK Driver chiama l'oggetto in conformità al protocollo GMTDAuthorization
. L'oggetto è responsabile di fornire il token di accesso richiesto.
In qualità di sviluppatore dell'app, sei tu a scegliere il modo in cui vengono generati i token. La tua implementazione dovrebbe offrire la possibilità 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 dei token previsti dal server Fleet Engine, consulta Creazione di un token web JSON (JWT) per l'autorizzazione.
L'ID provider è uguale all'ID progetto Google Cloud. Per ulteriori informazioni, consulta la guida rapida di Fleet Engine.
Nell'esempio seguente viene implementato un provider di token di accesso:
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
Crea un'istanza RidesharingDriverAPI
Per ottenere un'istanza GMTDVehicleReporter
, devi prima creare un'istanza GMTDRidesharingDriverAPI
utilizzando providerID,
vehicleID, driverContext e accessTokenProvider. Il providerID è uguale all'ID progetto Google Cloud. Puoi accedere all'istanza GMTDVehicleReporter
direttamente dall'API Driver.
L'esempio seguente crea un'istanza 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];
}
(Facoltativo) Ascolta gli eventi VehicleReporter
GMTDVehicleReporter
aggiorna periodicamente il veicolo quando locationTrackingEnabled
è true
. Per rispondere a questi aggiornamenti periodici, qualsiasi oggetto può sottoscrivere gli eventi GMTDVehicleReporter
rispettando il protocollo GMTDVehicleReporterListener
.
Puoi gestire i seguenti eventi:
vehicleReporter(_:didSucceed:)
Comunica all'app Driver che i servizi di backend hanno ricevuto correttamente la posizione e l'aggiornamento dello stato del veicolo.
vehicleReporter(_:didFail:withError:)
Informa il listener che un aggiornamento del veicolo non è riuscito. Finché il monitoraggio della posizione è abilitato,
GMTDVehicleReporter
continua a inviare i dati più recenti al backend di Fleet Engine.
L'esempio seguente gestisce questi eventi:
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
Aggiungi GMTDVeicoliReporter come listener a GMSRoadSnappedLocationProvider
Per fornire aggiornamenti di posizione all'SDK Driver, GMTDVehicleReporter
deve essere impostato come listener per 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
Attiva il monitoraggio della posizione
Per attivare il monitoraggio della posizione, la tua app può impostare locationTrackingEnabled
su true
su GMTDVehicleReporter
. GMTDVehicleReporter
invia automaticamente aggiornamenti sulla posizione.
Una volta che i servizi corrispondono e hanno assegnato il veicolo a una corsa, GMTDVehicleReporter
invia automaticamente gli aggiornamenti del percorso quando GMSNavigator
è in modalità di navigazione (quando una
destinazione è impostata su setDestinations
).
Il percorso impostato durante l'aggiornamento della corsa sarà lo stesso percorso dal conducente durante la sessione di navigazione.
Pertanto, affinché la condivisione del percorso funzioni correttamente, il tappeto impostato tramite setDestinations
deve corrispondere alla destinazione impostata nel backend di Fleet Engine.
Se locationTrackingEnabled
è impostato su true
, gli aggiornamenti relativi alle corse e ai veicoli vengono inviati al backend di Fleet Engine a intervalli regolari in base al valore impostato per locationUpdateInterval
. Se il criterio locationTrackingEnabled
è impostato su false
, gli aggiornamenti vengono interrotti e viene inviata una richiesta di aggiornamento finale del veicolo al backend di Fleet Engine per impostare lo stato del veicolo su GMTDVehicleState.offline
.
Consulta updateVehicleState
per considerazioni speciali sulla gestione degli errori quando il valore di locationTrackingEnabled
è impostato su false
.
L'esempio seguente attiva il monitoraggio della posizione:
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
Per impostazione predefinita, l'intervallo dei report è di 10 secondi, ma 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.
Aggiorna lo stato del veicolo
L'esempio seguente mostra come impostare lo stato del veicolo su ONLINE
.
Per informazioni dettagliate, visita la pagina 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
Quando la maschera è vuota può verificarsi un errore update_mask
e in genere si verifica per il primo aggiornamento dopo l'avvio. L'esempio seguente mostra 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
Disattiva gli aggiornamenti di posizione e porta il veicolo offline
L'app può disattivare gli aggiornamenti e portare il veicolo offline. Ad esempio, quando termina il turno di un conducente, la tua app può impostare locationTrackingEnabled
su false
. La disabilitazione degli aggiornamenti imposta anche lo stato del veicolo su OFFLINE
sul backend di Fleet Engine.
Swift
vehicleReporter.locationTrackingEnabled = false
Objective-C
_vehicleReporter.locationTrackingEnabled = NO;