Guida introduttiva all'SDK di Drive per Android

Puoi utilizzare l'SDK Driver per fornire navigazione e monitoraggio avanzati alla tua richiesta di avanzamento di viaggi e ordini. L'SDK Driver fornisce aggiornamenti sulla posizione del veicolo e sulle attività a Fleet Engine per la soluzione On-demand Rides and Deliveries Solution.

L'SDK Driver mantiene i servizi Fleet Engine e i 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 la corsa prosegue.

Requisiti minimi di sistema

Sul dispositivo mobile deve essere installato Android 6.0 (livello API 23) o versioni successive.

Configurazione della build e 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:

  1. Crea un nuovo progetto della console Google Cloud o selezionane uno esistente da utilizzare con l'SDK Driver. Attendi qualche minuto finché il nuovo progetto non è visibile nella console Google Cloud.

  2. Per eseguire l'app demo, il progetto deve avere accesso a Maps SDK per Android. Nella console Google Cloud, seleziona API e servizi > Libreria, poi cerca e attiva Maps SDK per Android.

  3. Ottieni una chiave API per il progetto selezionando API e servizi > Credenziali > Crea credenziali > Chiave API. Per ulteriori informazioni 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:

  1. 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>
    
  2. L'SDK Driver dipende dall'SDK di navigazione e questa dipendenza è configurata in modo tale che, se è necessaria una versione specifica dell'SDK di navigazione, dovrà essere definita esplicitamente nel file di configurazione della build come riportato di seguito. Se ometti il blocco di codice indicato, 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 ultime versioni di SDK Driver e SDK di navigazione sono stati sottoposti a test rigorosi prima delle release.

    Organizza di conseguenza la configurazione delle dipendenze del tuo sviluppo e rilascia gli ambienti.

    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 l'app possa fare riferimento in modo più sicuro. Non devi 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 pagina relativa ai 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:

  1. Apri il file build.gradle a livello di directory principale e aggiungi il seguente codice all'elemento dependencies in buildscript.

    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")
        }
    }
    
  2. Apri il file build.gradle a livello di app e aggiungi il seguente codice all'elemento plugins.

    Trendy

    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
    

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. Se usi Android Studio, sincronizza il progetto con Gradle.

  4. Apri local.properties nella directory a livello di progetto, quindi aggiungi il codice seguente. Sostituisci YOUR_API_KEY con la tua chiave API.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. Nel file AndroidManifest.xml, vai a com.google.android.geo.API_KEY e aggiorna l'attributo android: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 di attribuzione e le licenze open source nella sezione delle note legali dell'app. È meglio 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, potresti dover 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 del progetto Google Cloud). Per ulteriori dettagli sulla configurazione del progetto Google Cloud, consulta Autenticazione e autorizzazione.

Prima di utilizzare Driver SDK, devi inizializzare l'SDK di navigazione. Per inizializzare l'SDK:

  1. Ottieni un oggetto Navigator da NavigationApi.

    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
        }
      },
    )
    
  2. Crea un oggetto DriverContext e compila 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()
    
  3. Utilizza l'oggetto DriverContext per inizializzare *DriverApi.

    Java

    RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
    

    Kotlin

    val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
    
  4. Ottieni RidesharingVehicleReporter dall'oggetto API. (*VehicleReporter estende NavigationVehicleReporter.)

    Java

    RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
    

    Kotlin

    val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
    

Autenticazione con AuthTokenFactory

Quando l'SDK Driver genera aggiornamenti della posizione, deve inviare questi aggiornamenti al server di Fleet Engine. Per autenticare queste richieste, l'SDK del driver chiamerà un'istanza fornita dal chiamante di AuthTokenFactory. La fabbrica è responsabile della generazione dei token di autenticazione al momento dell'aggiornamento della località.

La modalità di generazione dei token sarà specifica per la situazione di ogni sviluppatore. Tuttavia, l'implementazione dovrà probabilmente:

  • Recuperare un token di autenticazione, possibilmente in formato JSON, da un server HTTPS
  • analizza e memorizza nella cache il token
  • aggiorna il token alla scadenza

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

Ecco uno schema di implementazione di un 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 il riutilizzo. Il token viene recuperato se precedente entro 10 minuti dalla data di scadenza.

La tua implementazione potrebbe fare le cose in modo diverso, ad esempio utilizzare un thread in background per aggiornare i token.

Le eccezioni in AuthTokenFactory verranno trattate come temporanee, a meno che non si verifichino ripetute. Dopo una serie di tentativi, l'SDK del driver suppone che l'errore è permanente e smette di tentare di inviare aggiornamenti.

Segnalazione di stato ed errori con StatusListener

Poiché l'SDK Driver esegue azioni in background, utilizza StatusListener per attivare 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) o comportare l'interruzione definitiva degli aggiornamenti della posizione (ad esempio VEHICLE_NOT_FOUND, che indica un errore di configurazione).

Fornisci un'implementazione facoltativa di tipo StatusListener, 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 Driver utilizza SSL/TLS per comunicare in modo sicuro con il server Fleet Engine. Le versioni precedenti di Android (versione API 19 o 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 aggiornamenti posizione

Dopo aver creato un'istanza *VehicleReporter, abilitare gli aggiornamenti della località è 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 se chiami 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 del report è di 10 secondi. L'intervallo del report può essere modificato con reporter.setLocationReportingInterval(long, TimeUnit). L'intervallo di aggiornamento minimo supportato è di 5 secondi. Aggiornamenti più frequenti possono causare richieste ed errori più lenti.

Disattivazione degli aggiornamenti della posizione in corso...

Al termine del turno del conducente, puoi interrompere gli aggiornamenti della posizione e contrassegnare il veicolo come offline chiamando il numero DeliveryVehicleReporter.disableLocationTracking o RidesharingVehicleReporter.disableLocationTracking.

Con questa chiamata verrà pianificato un aggiornamento finale per la consegna immediata, indicando che il veicolo è offline. Questo aggiornamento non conterrà la posizione dell'utente.

Impostazione dello stato del veicolo

Quando gli aggiornamenti della posizione sono abilitati, l'impostazione dello stato del veicolo su ONLINE rende il veicolo disponibile per le query SearchVehicles; allo stesso modo, se contrassegni un veicolo come OFFLINE, il veicolo 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 verrà propagata al successivo aggiornamento della posizione.

Se contrassegni un veicolo come ONLINE quando il monitoraggio della posizione non è attivo, verrà visualizzato un IllegalStateException. Un veicolo può essere contrassegnato come OFFLINE quando il monitoraggio della posizione non è ancora attivato o esplicitamente disattivato. Questo comporterà un aggiornamento immediato. Una chiamata a RidesharingVehicleReporter.disableLocationTracking() imposta lo stato del veicolo su OFFLINE.

Tieni presente che setVehicleState restituisce immediatamente e gli aggiornamenti vengono eseguiti nel thread di aggiornamento della posizione. In modo simile alla gestione degli errori per gli aggiornamenti delle località, gli errori di aggiornamento dello stato del veicolo vengono propagati utilizzando il set di StatusListener fornito facoltativamente in DriverContext.