Puedes usar el SDK de Driver para mejorar la navegación y el seguimiento de tu aplicación de Progreso de viaje y pedido. El SDK de Driver proporciona actualizaciones de tareas y ubicación del vehículo a On-demand Rides and Deliveries Solution Fleet Engine.
El SDK de Driver mantiene a los servicios de Fleet Engine y tus servicios personalizados al tanto de la ubicación y el estado del vehículo. Por ejemplo, el vehículo puede ser ONLINE
o OFFLINE
, y la ubicación del vehículo cambia a medida que avanza el viaje.
Requisitos mínimos del sistema
El dispositivo móvil debe ejecutar Android 5.0 (nivel de API 21) o una versión posterior.
Configuración de Maven
Las versiones 4.99 y posteriores del SDK de Driver están disponibles en el repositorio de Maven de Google.
Gradle
Agrega lo siguiente a tu archivo build.gradle
:
repositories {
...
google()
}
Maven
Agrega lo siguiente a tu archivo pom.xml
:
<project>
...
<repositories>
<repository>
<id>google-maven-repository</id>
<url>https://maven.google.com</url>
</repository>
</repositories>
...
</project>
Configuración del proyecto
Para usar el SDK de Driver, tu app debe orientarse a minSdkVersion
21 o una versión posterior.
Para ejecutar una app compilada con el SDK de Driver, el dispositivo Android debe tener instalados los Servicios de Google Play.
Configura tu proyecto de desarrollo
Si deseas configurar tu proyecto de desarrollo y obtener una clave de API para el proyecto en la consola de Google Cloud, sigue estos pasos:
Crea un proyecto nuevo de la consola de Google Cloud o selecciona uno existente para usar con el SDK de Driver. Espera unos minutos hasta que el proyecto nuevo sea visible en la consola de Google Cloud.
A fin de ejecutar la app de demostración, tu proyecto debe tener acceso al SDK de Maps para Android. En la consola de Google Cloud, selecciona APIs y servicios > Biblioteca y, luego, busca y habilita el SDK de Maps para Android.
Para obtener una clave de API para el proyecto, selecciona APIs y servicios > Credenciales > Crear credenciales > Clave de API. Consulta Obtén una clave de API para conocer más detalles sobre cómo conseguir una clave de API.
Agrega el SDK de Driver a tu app
El SDK de Driver está disponible en un repositorio de Maven privado. El repositorio incluye los archivos del Modelo de objetos del proyecto (.pom) del SDK y Javadocs. Para agregar el SDK de Driver a tu app, haz lo siguiente:
Agrega la siguiente dependencia a tu configuración de Gradle o Maven, y reemplaza el marcador de posición
VERSION_NUMBER
por la versión deseada del SDK de Driver.Gradle
Agrega lo siguiente a tu
build.gradle
:dependencies { ... implementation 'com.google.android.libraries.mapsplatform.transportation:transportation-driver:VERSION_NUMBER' }
Maven
Agrega lo siguiente a tu
pom.xml
:<dependencies> ... <dependency> <groupId>com.google.android.libraries.mapsplatform.transportation</groupId> <artifactId>transportation-driver</artifactId> <version>VERSION_NUMBER</version> </dependency> </dependencies>
Agrega la clave de API a tu app
Una vez que hayas agregado el SDK de Driver a tu app, agrega la clave de API a esta. Debes usar la clave de API del proyecto que obtuviste cuando configuraste tu proyecto de desarrollo.
En esta sección, se describe cómo almacenar tu clave de API para que tu app pueda hacer referencia a ella de manera más segura. No debes verificarla en tu sistema de control de versión. Debe almacenarse en el archivo local.properties
, que se encuentra en el directorio raíz de tu proyecto. Para obtener más información sobre el archivo local.properties
, consulta los archivos de propiedades de Gradle.
Para optimizar esta tarea, puedes usar el complemento Secrets Gradle para Android.
Para instalar el complemento y almacenar tu clave de API, haz lo siguiente:
Abre el archivo
build.gradle
de nivel de raíz y agrega el siguiente código al elementodependencies
enbuildscript
.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") } }
Abre el archivo
build.gradle
a nivel de la app y agrega el siguiente código al elementoplugins
.Groovy
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
Kotlin
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
Si usas Android Studio, sincroniza tu proyecto con Gradle.
Abre
local.properties
en el directorio de nivel de proyecto y, luego, agrega el siguiente código. ReemplazaYOUR_API_KEY
por tu clave de API.MAPS_API_KEY=YOUR_API_KEY
En tu archivo
AndroidManifest.xml
, ve acom.google.android.geo.API_KEY
y actualiza el atributoandroid:value
de la siguiente manera:<meta-data android:name="com.google.android.geo.API_KEY" android:value="${MAPS_API_KEY}" />
En el siguiente ejemplo, se muestra un manifiesto completo para una app de ejemplo:
<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>
Incluye las atribuciones requeridas en tu app
Si usas el SDK de Driver en tu app, debes incluir texto de atribución y licencias de código abierto como parte de la sección de avisos legales de la app. Es mejor incluir las atribuciones como un elemento de menú independiente o como parte de un elemento de menú Acerca de.
Puedes encontrar el texto de atribución y las licencias de código abierto necesarios en el archivo ZIP del SDK de Driver:
NOTICE.txt
LICENSES.txt
Dependencias
Si usas ProGuard para optimizar tus compilaciones, es posible que debas agregar las siguientes líneas al archivo de configuración de ProGuard:
-dontwarn com.google.**
-dontwarn okio.**
El nivel de API mínimo admitido es 21.
Inicializa el SDK
Se requiere un ID de proveedor (por lo general, el ID del proyecto de Google Cloud) para inicializar el objeto DriverContext
. Para obtener más detalles sobre cómo configurar el proyecto de Google Cloud, consulta Autenticación y autorización.
Antes de usar el SDK de Driver, debes inicializar el SDK de Navigation. Cómo inicializar el SDK:
Obtén un objeto
Navigator
deNavigationApi
.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 objeto
DriverContext
y propaga los campos obligatorios.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 el objeto
DriverContext
para inicializar*DriverApi
.Java
RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
Kotlin
val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
Obtén el
RidesharingVehicleReporter
del objeto de la API. (*VehicleReporter
extiendeNavigationVehicleReporter
).Java
RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
Kotlin
val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
Autentica con AuthTokenFactory
Cuando el SDK de Driver genera actualizaciones de ubicación, debe enviarlas al servidor de Fleet Engine. Para autenticar estas solicitudes, el
SDK de Driver llamará a una instancia de AuthTokenFactory
proporcionada por el emisor.
La fábrica es responsable de generar tokens de autenticación en el momento de la actualización de la ubicación.
La forma exacta en que se generan los tokens será específica para la situación de cada desarrollador. Sin embargo, es probable que la implementación deba hacer lo siguiente:
- recuperar un token de autenticación, posiblemente en formato JSON, desde un servidor HTTPS
- analizar y almacenar en caché el token
- actualizar el token cuando venza
Para obtener detalles de los tokens que espera el servidor de Fleet Engine, consulta Crea un token web JSON (JWT) para la autorización.
A continuación, se muestra una implementación de esqueleto de 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)
}
}
}
Esta implementación en particular utiliza el cliente HTTP de Java integrado para recuperar un token en formato JSON desde el servidor de autenticación del desarrollador. El token se guarda para su reutilización. El token se vuelve a recuperar si el anterior está dentro de los 10 minutos de su hora de vencimiento.
Tu implementación puede hacer cosas de manera diferente, como usar un subproceso en segundo plano para actualizar los tokens.
Las excepciones en AuthTokenFactory
se tratarán como transitorias, a menos que ocurran de manera reiterada. Después de varios intentos, el SDK de Driver supondrá que el error es permanente y dejará de intentar enviar actualizaciones.
Status y Error Reporting con StatusListener
Dado que el SDK de Driver realiza acciones en segundo plano, usa StatusListener
para activar notificaciones cuando ocurran ciertos eventos, como errores, advertencias o mensajes de depuración. Los errores pueden ser de naturaleza transitoria (como BACKEND_CONNECTIVITY_ERROR
) o hacer que las actualizaciones de ubicación se detengan de forma permanente (como VEHICLE_NOT_FOUND
, que indica un error de configuración).
Proporcionas una implementación opcional de StatusListener
como la siguiente:
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.
}
}
Notas sobre SSL/TLS
De forma interna, la implementación del SDK de Driver usa SSL/TLS para comunicarse de forma segura con el servidor de Fleet Engine. Las versiones anteriores de Android (nivel de API 19 o anteriores) pueden requerir un parche SecurityProvider
para comunicarse con el servidor. Debes consultar este artículo para obtener más información sobre cómo trabajar con SSL en Android. Además, se incluyen muestras de código para aplicar parches al proveedor de seguridad.
Cómo habilitar las actualizaciones de ubicación
Una vez que tengas una instancia de *VehicleReporter
, es sencillo habilitar las actualizaciones de ubicación:
Java
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
Kotlin
val reporter = ...
reporter.enableLocationTracking()
Las actualizaciones de ubicación se envían a intervalos regulares cuando el estado del vehículo es ONLINE
. Ten en cuenta que la llamada a reporter.enableLocationTracking()
no
establece automáticamente el estado del vehículo en ONLINE
. Debes configurar el estado del vehículo de forma explícita.
De forma predeterminada, el intervalo de informes es de 10 segundos. El intervalo de informes se puede cambiar con reporter.setLocationReportingInterval(long, TimeUnit)
. El intervalo de actualización mínimo admitido es de 5 segundos. Las actualizaciones más frecuentes pueden
generar solicitudes más lentas y errores.
Cómo inhabilitar las actualizaciones de ubicación
Cuando termine el turno del conductor, se podrán detener las actualizaciones de ubicación y se podrá marcar el vehículo como sin conexión llamando a DeliveryVehicleReporter.disableLocationTracking
o RidesharingVehicleReporter.disableLocationTracking
.
Esta llamada hará que se programe una actualización final para la entrega inmediata, lo que indica que el vehículo está sin conexión. Esta actualización no incluirá la ubicación del usuario.
Cómo configurar el estado del vehículo
Cuando las actualizaciones de ubicación están habilitadas, establecer el estado del vehículo en ONLINE
hará que el vehículo esté disponible para las consultas SearchVehicles
. Del mismo modo, marcar un vehículo como OFFLINE
marcará el vehículo como no disponible.
Puedes configurar el estado del vehículo en el servidor (consulta Cómo actualizar un vehículo) o directamente en el SDK de Driver:
Java
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
reporter.setVehicleState(VehicleState.ONLINE);
Kotlin
val reporter = ...
reporter.enableLocationTracking()
reporter.setVehicleState(VehicleState.ONLINE)
Cuando las actualizaciones de ubicación estén habilitadas, se propagará una llamada a setVehicleState
en la próxima actualización de ubicación.
Marcar un vehículo como ONLINE
cuando el seguimiento de ubicación no está habilitado generará una IllegalStateException
. Un vehículo se puede marcar como OFFLINE
cuando el seguimiento de ubicación aún no está habilitado o inhabilitado de forma explícita. Esto generará una actualización inmediata. Una llamada a RidesharingVehicleReporter.disableLocationTracking()
establecerá el estado del vehículo en OFFLINE
.
Ten en cuenta que setVehicleState
se muestra de inmediato y que las actualizaciones se realizan en el subproceso de actualización de ubicación. Al igual que con el manejo de errores de las actualizaciones de ubicaciones, los errores que actualizan el estado del vehículo se propagan mediante el StatusListener
opcional que se establece en DriverContext
.