Premiers pas avec le SDK Driver pour Android

Vous pouvez utiliser le SDK Driver pour améliorer la navigation et le suivi dans votre application de trajet et de progression de la commande. Le SDK Driver fournit des mises à jour de l'emplacement et des tâches des véhicules à la solution On-demand Rides and Deliveries Fleet Engine.

Le SDK Driver permet aux services Fleet Engine et à vos services personnalisés de connaître l'emplacement et l'état du véhicule. Par exemple, le véhicule peut être ONLINE ou OFFLINE, et sa position change au fur et à mesure du trajet.

Configuration système minimale requise

L'appareil mobile doit être équipé d'Android 6.0 (niveau d'API 23) ou version ultérieure.

Configuration de la compilation et des dépendances

Les versions 4.99 et ultérieures du SDK Driver sont disponibles dans le dépôt Maven de Google.

Gradle

Ajoutez le code ci-dessous à votre fichier build.gradle :

repositories {
    ...
    google()
}

Maven

Ajoutez le code ci-dessous à votre fichier pom.xml :

<project>
  ...
  <repositories>
    <repository>
      <id>google-maven-repository</id>
      <url>https://maven.google.com</url>
    </repository>
  </repositories>
  ...
</project>

Configuration du projet

Pour utiliser le SDK Driver, votre application doit cibler minSdkVersion 23 ou une version ultérieure.

Pour exécuter une application créée avec le SDK Driver, les services Google Play doivent être installés sur l'appareil Android.

Configurer votre projet de développement

Pour configurer votre projet de développement et obtenir une clé API pour le projet dans la console Google Cloud:

  1. Créez un projet dans la console Google Cloud ou sélectionnez un projet existant à utiliser avec le SDK Driver. Attendez quelques minutes que le nouveau projet soit visible dans la console Google Cloud.

  2. Pour que vous puissiez exécuter l'application de démonstration, votre projet doit avoir accès au SDK Maps pour Android. Dans la console Google Cloud, sélectionnez API et services > Bibliothèque, puis recherchez et activez le SDK Maps pour Android.

  3. Obtenez une clé API pour le projet en sélectionnant API et services > Identifiants > Créer des identifiants > Clé API. Pour savoir comment obtenir une clé API, consultez Obtenir une clé API.

Ajouter le SDK Driver à votre application

Le SDK Driver est disponible dans le dépôt Maven de Google. Le dépôt inclut les fichiers .pom (Project Object Model) du SDK, ainsi que des documents Javadocs. Pour ajouter le SDK Driver à votre application:

  1. Ajoutez la dépendance suivante à votre configuration Gradle ou Maven, en remplaçant l'espace réservé VERSION_NUMBER par la version souhaitée du SDK Driver.

    Gradle

    Ajoutez les éléments suivants à votre build.gradle :

    dependencies {
      ...
      implementation 'com.google.android.libraries.mapsplatform.transportation:transportation-driver:VERSION_NUMBER'
    }
    

    Maven

    Ajoutez les éléments suivants à votre pom.xml :

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-driver</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  2. Le SDK Driver dépend du SDK Navigation. Cette dépendance est configurée de sorte que si une version spécifique du SDK Navigation est nécessaire, elle doit être explicitement définie dans le fichier de configuration de compilation comme ci-dessous. Si vous omettez le bloc de code mentionné, le projet pourra toujours télécharger la dernière version du SDK Navigation dans la version majeure. Notez que les comportements combinés des dernières versions du SDK Drive et du SDK Navigation ont été soumis à des tests rigoureux avant leur publication.

    Organisez la configuration des dépendances de vos environnements de développement et de publication en conséquence.

    Gradle

    Ajoutez les éléments suivants à votre build.gradle :

    dependencies {
      ...
      implementation 'com.google.android.libraries.navigation:navigation:5.0.0'
    }
    

    Maven

    Ajoutez les éléments suivants à votre pom.xml :

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.navigation</groupId>
        <artifactId>navigation</artifactId>
        <version>5.0.0</version>
      </dependency>
    </dependencies>
    

Ajouter la clé API à votre application

Une fois le SDK Driver ajouté à votre application, ajoutez la clé API à celle-ci. Vous devez utiliser la clé API du projet que vous avez obtenue lors de la configuration de votre projet de développement.

Cette section explique comment stocker votre clé API afin qu'elle puisse être référencée de manière plus sécurisée par votre application. Vous ne devez pas l'enregistrer dans votre système de contrôle des versions. Il doit être stocké dans le fichier local.properties, qui se trouve dans le répertoire racine de votre projet. Pour en savoir plus sur le fichier local.properties, consultez Fichiers de propriétés Gradle.

Pour vous faciliter la tâche, vous pouvez utiliser le plug-in Secrets Gradle pour Android.

Pour installer le plug-in et stocker votre clé API :

  1. Ouvrez le fichier build.gradle au niveau racine et ajoutez le code suivant à l'élément dependencies sous buildscript.

    Groovy

    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. Ouvrez le fichier build.gradle au niveau de l'application et ajoutez le code suivant à l'élément plugins.

    Groovy

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

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. Si vous utilisez Android Studio, synchronisez votre projet avec Gradle.

  4. Ouvrez local.properties dans votre répertoire au niveau du projet, puis ajoutez le code suivant. Remplacez YOUR_API_KEY par votre clé API.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. Dans votre fichier AndroidManifest.xml, accédez à com.google.android.geo.API_KEY et mettez à jour l'attribut android:value comme suit:

    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="${MAPS_API_KEY}" />
    

L'exemple suivant présente un fichier manifeste complet pour une application exemple:

<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>

Inclure les attributions requises dans votre application

Si vous utilisez le SDK Driver dans votre application, vous devez inclure le texte d'attribution et les licences Open Source dans la section des mentions légales de votre application. Il est préférable d'inclure les attributions dans un élément de menu indépendant ou dans un élément de menu About (À propos).

Les informations sur les licences se trouvent dans le fichier "third_party_licenses.txt" du fichier AAR désarchivé.

Pour savoir comment inclure des notifications Open Source, consultez la page https://developers.google.com/android/guides/opensource.

Dépendances

Si vous utilisez ProGuard pour optimiser vos builds, vous devrez peut-être ajouter les lignes suivantes à votre fichier de configuration ProGuard:

-dontwarn com.google.**
-dontwarn okio.**

Le niveau d'API minimal accepté est 23.

Initialiser le SDK

Un ID de fournisseur (généralement l'ID du projet Google Cloud) est requis pour initialiser l'objet DriverContext. Pour en savoir plus sur la configuration du projet Google Cloud, consultez la page Authentification et autorisation.

Avant d'utiliser le SDK Driver, vous devez d'abord initialiser le SDK Navigation. Pour initialiser le SDK, procédez comme suit :

  1. Obtenez un objet Navigator à partir de 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. Créez un objet DriverContext en renseignant les champs obligatoires.

    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. Utilisez l'objet DriverContext pour initialiser *DriverApi.

    Java

    RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
    

    Kotlin

    val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
    
  4. Obtenez RidesharingVehicleReporter à partir de l'objet API. (*VehicleReporter étend NavigationVehicleReporter.)

    Java

    RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
    

    Kotlin

    val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
    

Authentification avec AuthTokenFactory

Lorsque le SDK Driver génère des mises à jour de position, il doit les envoyer au serveur Fleet Engine. Pour authentifier ces requêtes, le SDK Driver appelle une instance de AuthTokenFactory fournie par l'appelant. La fabrique est chargée de générer des jetons d'authentification au moment de la mise à jour de l'emplacement.

Le mode de génération exact des jetons dépend de la situation de chaque développeur. Cependant, l'implémentation devra probablement:

  • Extraire un jeton d'authentification, éventuellement au format JSON, à partir d'un serveur HTTPS
  • analyser et mettre en cache le jeton ;
  • actualiser 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.

Voici un squelette d'implémentation d'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)
    }
  }
}

Cette implémentation particulière utilise le client HTTP Java intégré pour récupérer un jeton au format JSON à partir du serveur d'authentification du développeur. Le jeton est enregistré pour être réutilisé. Le jeton est à nouveau récupéré si l'ancien jeton se trouve dans les 10 minutes précédant son délai d'expiration.

Votre implémentation peut se comporter différemment, par exemple en utilisant un thread d'arrière-plan pour actualiser les jetons.

Les exceptions dans AuthTokenFactory seront traitées comme temporaires, sauf si elles se produisent de façon répétée. Après plusieurs tentatives, le SDK Drive supposera que l'erreur est permanente et cessera toute tentative d'envoi de mises à jour.

Rapports d'état et d'erreurs avec StatusListener

Étant donné que le SDK Driver effectue des actions en arrière-plan, utilisez StatusListener pour déclencher des notifications lorsque certains événements se produisent, tels que des erreurs, des avertissements ou des messages de débogage. Les erreurs peuvent être de nature temporaire (par exemple, BACKEND_CONNECTIVITY_ERROR) ou entraîner l'arrêt permanent des mises à jour de la position (telles que VEHICLE_NOT_FOUND, indiquant une erreur de configuration).

Vous fournissez une implémentation StatusListener facultative comme celle-ci:

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.
  }
}

Remarques sur SSL/TLS

En interne, la mise en œuvre du SDK Driver utilise SSL/TLS pour communiquer de manière sécurisée avec le serveur Fleet Engine. Les anciennes versions d'Android (version 19 ou antérieure de l'API) peuvent nécessiter un correctif SecurityProvider pour pouvoir communiquer avec le serveur. Pour en savoir plus sur l'utilisation de SSL sous Android, consultez cet article. Il contient également des exemples de code permettant d'appliquer un correctif au fournisseur de solutions de sécurité.

Activation des mises à jour de la position...

Une fois que vous disposez d'une instance *VehicleReporter, l'activation des mises à jour de la position est simple:

Java

RidesharingVehicleReporter reporter = ...;

reporter.enableLocationTracking();

Kotlin

val reporter = ...

reporter.enableLocationTracking()

Les mises à jour de la position sont envoyées à intervalle régulier lorsque l'état du véhicule est ONLINE. Notez que l'appel de reporter.enableLocationTracking() ne définit pas automatiquement l'état du véhicule sur ONLINE. Vous devez définir l'état du véhicule explicitement.

Par défaut, l'intervalle du rapport est de 10 secondes. L'intervalle de reporting peut être modifié avec reporter.setLocationReportingInterval(long, TimeUnit). L'intervalle minimal de mise à jour accepté est de 5 secondes. Des mises à jour plus fréquentes peuvent ralentir les requêtes et provoquer des erreurs.

Désactivation des mises à jour de la position géographique

Une fois le quart de travail du conducteur terminé, vous pouvez arrêter les mises à jour de la position et marquer le véhicule comme étant hors connexion en appelant DeliveryVehicleReporter.disableLocationTracking ou RidesharingVehicleReporter.disableLocationTracking.

Cet appel entraînera la planification d'une dernière mise à jour pour une livraison immédiate, indiquant que le véhicule est hors connexion. Cette mise à jour ne contiendra pas la position de l'utilisateur.

Définir l'état du véhicule

Lorsque les mises à jour de position sont activées, définir l'état du véhicule sur ONLINE le rendra disponible pour les requêtes SearchVehicles. De même, si vous marquez un véhicule avec la valeur OFFLINE, il est marqué comme indisponible.

Vous pouvez définir l'état du véhicule côté serveur (voir Mettre à jour un véhicule) ou directement dans le SDK Driver:

Java

RidesharingVehicleReporter reporter = ...;

reporter.enableLocationTracking();
reporter.setVehicleState(VehicleState.ONLINE);

Kotlin

val reporter = ...

reporter.enableLocationTracking()
reporter.setVehicleState(VehicleState.ONLINE)

Lorsque les mises à jour de la position sont activées, un appel à setVehicleState se propage à la prochaine mise à jour de la position.

Marquer un véhicule comme ONLINE lorsque le suivi de la localisation n'est pas activé génère une IllegalStateException. Un véhicule peut être marqué comme OFFLINE lorsque le suivi de la localisation n'est pas encore activé ou qu'il est explicitement désactivé. Cela entraînera une mise à jour immédiate. Un appel à RidesharingVehicleReporter.disableLocationTracking() définit l'état du véhicule sur OFFLINE.

Notez que setVehicleState est renvoyé immédiatement et que les mises à jour sont effectuées sur le thread de mise à jour de l'établissement. Comme pour le traitement des erreurs de mise à jour de position, les erreurs mettant à jour l'état du véhicule sont propagées à l'aide de l'StatusListener défini en option dans le DriverContext.