Puoi utilizzare l'SDK Driver per fornire funzionalità di navigazione e monitoraggio avanzate nella tua applicazione Trip and Order Progress. L'SDK Driver fornisce aggiornamenti sulla posizione dei veicoli e sulle attività in On-demand Rides and Deliveries Solution Fleet Engine.
L'SDK Driver tiene informati i servizi Fleet Engine e i tuoi servizi personalizzati 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
Sul dispositivo mobile deve essere installato Android 6.0 (livello API 23) o versioni successive.
Configurazione e configurazione delle dipendenze
Le versioni dell'SDK Driver 4.99 e successive sono disponibili nel Repository Maven di Google.
Gradle
Aggiungi quanto segue al tuo file build.gradle
:
repositories {
...
google()
}
Maven
Aggiungi quanto segue al tuo file pom.xml
:
<project>
...
<repositories>
<repository>
<id>google-maven-repository</id>
<url>https://maven.google.com</url>
</repository>
</repositories>
...
</project>
Configurazione progetto
Per utilizzare l'SDK Driver, la tua app deve avere come target
minSdkVersion
23 o versioni successive.
Per eseguire un'app creata con l'SDK Driver, sul dispositivo Android deve essere installato Google Play Services.
Configura il progetto di sviluppo
Per configurare il progetto di sviluppo e ottenere una chiave API per il progetto nella console Google Cloud:
Crea un nuovo progetto della console Google Cloud o selezionane uno esistente da utilizzare con l'SDK di Driver. Attendi qualche minuto finché il nuovo progetto non è visibile nella console Google Cloud.
Per eseguire l'app demo, il tuo progetto deve avere accesso a Maps SDK for Android. Nella console Google Cloud, seleziona API e servizi > Libreria, quindi cerca e abilita Maps SDK for Android.
Ottieni una chiave API per il progetto selezionando API e servizi > Credenziali > Crea credenziali > Chiave API. Per saperne di più su come ottenere una chiave API, consulta Ottenere una chiave API.
Aggiungi l'SDK Driver alla tua app
L'SDK Driver è disponibile nel Repository Maven di Google. Il repository include i file Project Object Model (.pom) e Javadocs dell'SDK. Per aggiungere l'SDK Driver alla tua app:
Aggiungi la seguente dipendenza alla configurazione Gradle o Maven, sostituendo il segnaposto
VERSION_NUMBER
con la versione desiderata dell'SDK Driver.Gradle
Aggiungi il seguente codice a
build.gradle
:dependencies { ... implementation 'com.google.android.libraries.mapsplatform.transportation:transportation-driver:VERSION_NUMBER' }
Maven
Aggiungi il seguente codice a
pom.xml
:<dependencies> ... <dependency> <groupId>com.google.android.libraries.mapsplatform.transportation</groupId> <artifactId>transportation-driver</artifactId> <version>VERSION_NUMBER</version> </dependency> </dependencies>
L'SDK Driver dipende dall'SDK di navigazione, questa dipendenza è configurata in modo tale che, se è necessaria una versione specifica dell'SDK di navigazione, questa deve essere definita esplicitamente nel file di configurazione della build come segue. Se il blocco di codice indicato viene omesso, il progetto potrà scaricare sempre la versione più recente dell'SDK di navigazione all'interno della versione di release principale. Tieni presente che i comportamenti combinati delle versioni più recenti di Driver SDK e Navigator SDK sono stati sottoposti a test rigorosi prima delle loro release.
Organizza la configurazione delle dipendenze nei tuoi ambienti di sviluppo e rilascio di conseguenza.
Gradle
Aggiungi il seguente codice a
build.gradle
:dependencies { ... implementation 'com.google.android.libraries.navigation:navigation:5.0.0' }
Maven
Aggiungi il seguente codice a
pom.xml
:<dependencies> ... <dependency> <groupId>com.google.android.libraries.navigation</groupId> <artifactId>navigation</artifactId> <version>5.0.0</version> </dependency> </dependencies>
Aggiungi la chiave API all'app
Dopo aver aggiunto l'SDK Driver all'app, aggiungi la chiave API all'app. Devi utilizzare la chiave API del progetto che hai ottenuto durante la configurazione del progetto di sviluppo.
Questa sezione descrive come archiviare la chiave API in modo che la tua app possa fare riferimento in modo più sicuro. Non controllare la chiave API nel sistema di controllo della versione. Dovrebbe essere archiviato nel file local.properties
, che si trova nella directory radice del progetto. Per ulteriori informazioni sul file local.properties
, consulta la sezione File delle proprietà di Gradle.
Per semplificare questa attività, puoi utilizzare il plug-in Secrets Gradle per Android.
Per installare il plug-in e memorizzare la chiave API:
Apri il file
build.gradle
di livello principale e aggiungi il seguente codice all'elementodependencies
inbuildscript
.Trendy
buildscript { dependencies { // ... classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.0" } }
Kotlin
buildscript { dependencies { // ... classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.0") } }
Apri il file
build.gradle
a livello di app e aggiungi il seguente codice all'elementoplugins
.Trendy
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
Kotlin
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
Se utilizzi Android Studio, sincronizza il progetto con Gradle.
Apri
local.properties
nella directory a livello di progetto, quindi aggiungi il codice seguente. SostituisciYOUR_API_KEY
con la tua chiave API.MAPS_API_KEY=YOUR_API_KEY
Nel file
AndroidManifest.xml
, vai acom.google.android.geo.API_KEY
e aggiorna l'attributoandroid:value
come segue:<meta-data android:name="com.google.android.geo.API_KEY" android:value="${MAPS_API_KEY}" />
L'esempio seguente mostra un manifest completo per un'app di esempio:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.driverapidemo">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/_AppTheme">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Includi le attribuzioni richieste nella tua app
Se utilizzi l'SDK Driver nella tua app, devi includere il testo dell'attribuzione e le licenze open source nella sezione Note legali dell'app. È preferibile includere le attribuzioni come voce di menu indipendente o come parte di una voce di menu Informazioni.
Le informazioni sulle licenze sono disponibili nel file "third_party_licenses.txt" del file AAR non archiviato.
Per informazioni su come includere notifiche open source, consulta la pagina https://developers.google.com/android/guides/opensource.
Dipendenze
Se utilizzi ProGuard per ottimizzare le build, potrebbe essere necessario aggiungere le seguenti righe al file di configurazione di ProGuard:
-dontwarn com.google.**
-dontwarn okio.**
Il livello API minimo supportato è 23.
Inizializzazione dell'SDK
Per inizializzare l'oggetto DriverContext
è necessario un ID provider (di solito l'ID progetto Google Cloud). Per ulteriori dettagli sulla configurazione del progetto Google Cloud, consulta Autenticazione e autorizzazione.
Prima di utilizzare l'SDK Driver, devi inizializzarlo. Per inizializzare l'SDK:
Ottieni un oggetto
Navigator
daNavigationApi
.Java
NavigationApi.getNavigator( this, // Activity new NavigationApi.NavigatorListener() { @Override public void onNavigatorReady(Navigator navigator) { // Keep a reference to the Navigator (used to configure and start nav) this.navigator = navigator; } } );
Kotlin
NavigationApi.getNavigator( this, // Activity object : NavigatorListener() { override fun onNavigatorReady(navigator: Navigator) { // Keep a reference to the Navigator (used to configure and start nav) this@myActivity.navigator = navigator } }, )
Crea un oggetto
DriverContext
, compilando i campi obbligatori.Java
DriverContext driverContext = DriverContext.builder(application) .setProviderId(providerId) .setVehicleId(vehicleId) .setAuthTokenFactory(authTokenFactory) .setNavigator(navigator) .setRoadSnappedLocationProvider( NavigationApi.getRoadSnappedLocationProvider(application)) .build();
Kotlin
val driverContext = DriverContext.builder(application) .setProviderId(providerId) .setVehicleId(vehicleId) .setAuthTokenFactory(authTokenFactory) .setNavigator(navigator) .setRoadSnappedLocationProvider(NavigationApi.getRoadSnappedLocationProvider(application)) .build()
Usa l'oggetto
DriverContext
per inizializzare*DriverApi
.Java
RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
Kotlin
val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
Ottieni
RidesharingVehicleReporter
dall'oggetto API. (*VehicleReporter
estendeNavigationVehicleReporter
.)Java
RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
Kotlin
val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
Autenticazione con AuthTokenFactory
Quando l'SDK Driver genera aggiornamenti di posizione, deve inviarli al server Fleet Engine. Per autenticare queste richieste, l'SDK Driver chiama un'istanza di AuthTokenFactory
fornita dal chiamante.
Il produttore è responsabile della generazione dei token di autenticazione al momento dell'aggiornamento della località.
Il modo esatto in cui vengono generati i token sarà specifico per la situazione di ogni sviluppatore. Tuttavia, l'implementazione dovrà probabilmente:
- recuperare un token di autenticazione, possibilmente in formato JSON, da un server HTTPS
- analizzare e memorizzare nella cache il token
- 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.
Di seguito è riportata una bozza di implementazione di AuthTokenFactory
:
Java
class JsonAuthTokenFactory implements AuthTokenFactory {
private String token; // initially null
private long expiryTimeMs = 0;
// This method is called on a thread whose only responsibility is to send
// location updates. Blocking is OK, but just know that no location updates
// can occur until this method returns.
@Override
public String getToken(AuthTokenContext authTokenContext) {
if (System.currentTimeMillis() > expiryTimeMs) {
// The token has expired, go get a new one.
fetchNewToken(authTokenContext.getVehicleId());
}
return token;
}
private void fetchNewToken(String vehicleId) {
String url =
new Uri.Builder()
.scheme("https")
.authority("yourauthserver.example")
.appendPath("token")
.appendQueryParameter("vehicleId", vehicleId)
.build()
.toString();
try (Reader r = new InputStreamReader(new URL(url).openStream())) {
com.google.gson.JsonObject obj
= com.google.gson.JsonParser.parseReader(r).getAsJsonObject();
token = obj.get("Token").getAsString();
expiryTimeMs = obj.get("TokenExpiryMs").getAsLong();
// The expiry time could be an hour from now, but just to try and avoid
// passing expired tokens, we subtract 10 minutes from that time.
expiryTimeMs -= 10 * 60 * 1000;
} catch (IOException e) {
// It's OK to throw exceptions here. The StatusListener you passed to
// create the DriverContext class will be notified and passed along the failed
// update warning.
throw new RuntimeException("Could not get auth token", e);
}
}
}
Kotlin
class JsonAuthTokenFactory : AuthTokenFactory() {
private var token: String = ""
private var expiryTimeMs: Long = 0
// This method is called on a thread whose only responsibility is to send
// location updates. Blocking is OK, but just know that no location updates
// can occur until this method returns.
override fun getToken(context: AuthTokenContext): String {
if (System.currentTimeMillis() > expiryTimeMs) {
// The token has expired, go get a new one.
fetchNewToken(authTokenContext.getVehicleId())
}
return token
}
fun fetchNewToken(vehicleId: String) {
val url =
Uri.Builder()
.scheme("https")
.authority("yourauthserver.example")
.appendPath("token")
.appendQueryParameter("vehicleId", vehicleId)
.build()
.toString()
try {
val reader = InputStreamReader(URL(url).openStream())
reader.use {
val obj = com.google.gson.JsonParser.parseReader(r).getAsJsonObject()
token = obj.get("ServiceToken").getAsString()
expiryTimeMs = obj.get("TokenExpiryMs").getAsLong()
// The expiry time could be an hour from now, but just to try and avoid
// passing expired tokens, we subtract 10 minutes from that time.
expiryTimeMs -= 10 * 60 * 1000
}
} catch (e: IOException) {
// It's OK to throw exceptions here. The StatusListener you passed to
// create the DriverContext class will be notified and passed along the failed
// update warning.
throw RuntimeException("Could not get auth token", e)
}
}
}
Questa particolare implementazione utilizza il client HTTP Java integrato per recuperare un token in formato JSON dal server di autenticazione dello sviluppatore. Il token viene salvato per essere riutilizzato. Il token viene recuperato nuovamente se il token precedente è trascorso entro 10 minuti dalla scadenza.
La tua implementazione potrebbe fare cose diverse, ad esempio usare un thread in background per aggiornare i token.
Le eccezioni in AuthTokenFactory
verranno trattate come temporanee, a meno che non si verifichino
ripetutamente. Dopo un certo numero di tentativi, l'SDK Driver presumerà che l'errore sia permanente e smetterà di provare a inviare aggiornamenti.
Stato ed Error Reporting con StatusListener
Poiché l'SDK Driver esegue azioni in background, utilizza StatusListener
per attivare le notifiche quando si verificano determinati eventi, come errori, avvisi o messaggi di debug. Gli errori possono essere di natura temporanea (ad esempio BACKEND_CONNECTIVITY_ERROR
) oppure causare l'interruzione definitiva degli aggiornamenti della posizione (ad esempio VEHICLE_NOT_FOUND
, indicando un errore di configurazione).
Devi fornire un'implementazione StatusListener
facoltativa come la seguente:
Java
class MyStatusListener implements StatusListener {
/** Called when background status is updated, during actions such as location reporting. */
@Override
public void updateStatus(
StatusLevel statusLevel, StatusCode statusCode, String statusMsg) {
// Status handling stuff goes here.
// StatusLevel may be DEBUG, INFO, WARNING, or ERROR.
// StatusCode may be DEFAULT, UNKNOWN_ERROR, VEHICLE_NOT_FOUND,
// BACKEND_CONNECTIVITY_ERROR, or PERMISSION_DENIED.
}
}
Kotlin
class MyStatusListener : StatusListener() {
/** Called when background status is updated, during actions such as location reporting. */
override fun updateStatus(statusLevel: StatusLevel, statusCode: StatusCode, statusMsg: String) {
// Status handling stuff goes here.
// StatusLevel may be DEBUG, INFO, WARNING, or ERROR.
// StatusCode may be DEFAULT, UNKNOWN_ERROR, VEHICLE_NOT_FOUND,
// BACKEND_CONNECTIVITY_ERROR, or PERMISSION_DENIED.
}
}
Note su SSL/TLS
Internamente, l'implementazione dell'SDK di Driver utilizza SSL/TLS per comunicare in modo sicuro con il server Fleet Engine. Le versioni precedenti di Android (API 19 o versioni precedenti) potrebbero richiedere una patch SecurityProvider
per poter comunicare con il server. Consulta questo articolo per ulteriori informazioni sull'utilizzo di SSL in Android. L'articolo contiene anche esempi di codice per l'applicazione di patch al provider di sicurezza.
Attivazione degli aggiornamenti della posizione
Una volta creata un'istanza *VehicleReporter
, l'attivazione degli aggiornamenti della posizione è semplice:
Java
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
Kotlin
val reporter = ...
reporter.enableLocationTracking()
Gli aggiornamenti sulla posizione vengono inviati a intervalli regolari quando lo stato del veicolo è ONLINE
. Tieni presente che quando chiami il numero reporter.enableLocationTracking()
, lo stato del veicolo non viene impostato automaticamente su ONLINE
. Devi
impostare lo stato del veicolo in modo esplicito.
Per impostazione predefinita, l'intervallo di report è di 10 secondi. L'intervallo di report può
essere modificato con reporter.setLocationReportingInterval(long, TimeUnit)
. L'intervallo di aggiornamento minimo supportato è di 5 secondi. Aggiornamenti più frequenti possono
ridurre le richieste e gli errori.
Disattivazione degli aggiornamenti della posizione
Al termine del turno del conducente, gli aggiornamenti di posizione possono essere arrestati e il veicolo può essere contrassegnato offline chiamando il numero DeliveryVehicleReporter.disableLocationTracking
o RidesharingVehicleReporter.disableLocationTracking
.
Questa chiamata comporterà la pianificazione dell'invio immediato di un aggiornamento finale, che indica che il veicolo è offline. Questo aggiornamento non conterrà la posizione dell'utente.
Impostazione dello stato del veicolo
Quando gli aggiornamenti della posizione sono abilitati e se imposti lo stato del veicolo su ONLINE
, il veicolo sarà disponibile per le query SearchVehicles
; in modo analogo, se contrassegni un veicolo come OFFLINE
, questo verrà contrassegnato come non disponibile.
Puoi impostare lo stato del veicolo sul lato server (vedi Aggiornare un veicolo) o direttamente nell'SDK Driver:
Java
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
reporter.setVehicleState(VehicleState.ONLINE);
Kotlin
val reporter = ...
reporter.enableLocationTracking()
reporter.setVehicleState(VehicleState.ONLINE)
Quando gli aggiornamenti della posizione sono abilitati, una chiamata a setVehicleState
viene propagata al successivo aggiornamento della posizione.
Se contrassegni un veicolo come ONLINE
quando il monitoraggio della posizione non è attivo, verrà restituito un IllegalStateException
. Un veicolo può essere contrassegnato come OFFLINE
se il monitoraggio della posizione non è ancora attivo o disattivato esplicitamente. Questa operazione comporterà
un aggiornamento immediato. Una chiamata al numero RidesharingVehicleReporter.disableLocationTracking()
imposterà lo stato del veicolo su OFFLINE
.
Tieni presente che setVehicleState
viene restituito immediatamente e gli aggiornamenti vengono eseguiti nel
thread di aggiornamento della posizione. Analogamente alla gestione degli errori degli aggiornamenti delle sedi, gli errori durante l'aggiornamento dello stato del veicolo vengono propagati utilizzando l'elemento StatusListener
fornito facoltativamente impostato in DriverContext
.