Cómo comenzar a usar el SDK de consumidor para Android

Puedes usar el SDK para consumidores a fin de compilar y ejecutar una app para consumidores básica integrada en los servicios de backend de la solución On-demand Rides and Deliveries. Puedes crear una app de progreso del viaje y el pedido que pueda mostrar un viaje activo, responder a las actualizaciones del viaje y manejar errores.

Debido a que el SDK de consumidor tiene una arquitectura modular, puedes usar las partes de la API que desees utilizar para tu app en particular y, luego, integrarlas a tus propias APIs, a los servicios de backend que proporciona Fleet Engine y a las APIs adicionales de Google Maps Platform.

Requisitos mínimos del sistema

El dispositivo móvil debe ejecutar Android 6.0 (nivel de API 23) o una versión posterior.

Configuración de compilaciones y dependencias

Las versiones 1.99.0 y posteriores del SDK para consumidores están disponibles mediante el repositorio de Maven de Google. El canal del repositorio privado que se usaba anteriormente dejó de estar disponible.

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 para consumidores de Android, tu app debe orientarse a minSdkVersion 23 o versiones posteriores.

Para ejecutar una app compilada con el SDK para consumidores, el dispositivo Android debe tener los Servicios de Google Play instalados.

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:

  1. Crea un proyecto nuevo de la consola de Google Cloud o selecciona un proyecto existente para usar con el SDK del consumidor. Espera unos minutos hasta que el proyecto nuevo sea visible en la consola de Google Cloud.

  2. Para 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.

  3. Para obtener una clave de API para el proyecto, selecciona APIs y servicios > Credenciales > Crear credenciales > Clave de API. Consulta Cómo obtener una clave de API para conocer más detalles al respecto.

Agrega el SDK para consumidores a tu app

El SDK para consumidores está disponible a través de un repositorio privado de Maven. El repositorio incluye los archivos del modelo de objetos del proyecto (.pom) del SDK y Javadocs. Para agregar el SDK de consumidor a tu app, haz lo siguiente:

  1. Configura tu entorno para acceder al repositorio de Maven host como se describe en la sección anterior.

    Si tienes una configuración de administración de dependencias centralizada declarada en settings.gradle, inhabilítala como se indica a continuación.

    • Quita el siguiente bloque de código de settings.gradle:

      import org.gradle.api.initialization.resolve.RepositoriesMode
      dependencyResolutionManagement {
          repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
          repositories {
              google()
              mavenCentral()
          }
      }
      
  2. 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 para consumidores.

    Gradle

    Agrega lo siguiente a tu build.gradle:

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

    Maven

    Agrega lo siguiente a tu pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-consumer</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  3. El SDK para consumidores depende del SDK de Maps. Esta dependencia se configura de tal manera que, si la versión del SDK de Maps no se define de forma explícita en el archivo de configuración de compilación, como se muestra a continuación, cuando se lance una versión nueva del SDK de Maps, el SDK para consumidores seguirá usando la versión mínima compatible del SDK de Maps que requiera.

    Gradle

    Agrega lo siguiente a tu build.gradle:

    dependencies {
      ...
      implementation 'com.google.android.gms:play-services-maps:18.1.0'
    }
    

    Maven

    Agrega lo siguiente a tu pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.gms</groupId>
        <artifactId>play-services-maps</artifactId>
        <version>18.1.0</version>
      </dependency>
    </dependencies>
    

Agrega la clave de API a tu app

Una vez que hayas agregado el SDK de consumidor a tu app, agrega la clave de API a tu app. Debes usar la clave de API del proyecto que obtuviste cuando configuraste el 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 registrarla en el 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:

  1. Abre el archivo build.gradle en el nivel raíz y agrega el siguiente código al elemento dependencies en 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. Abre el archivo build.gradle a nivel de la app y agrega el siguiente código al elemento plugins.

    Groovy

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

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. Si usas Android Studio, sincroniza tu proyecto con Gradle.

  4. Abre el archivo local.properties en el directorio de nivel de proyecto y, luego, agrega el siguiente código. Reemplaza YOUR_API_KEY por tu clave de API.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. En tu archivo AndroidManifest.xml, ve a com.google.android.geo.API_KEY y actualiza el atributo android: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.consumerapidemo">
    <uses-permission android:name="android.permission.ACCESS_FINE_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 aplicación

Si usas el SDK para consumidores en tu app, debes incluir el texto de atribución y las 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.

La información sobre las licencias se puede encontrar en el archivo "third_party_licenses.txt" en el archivo AAR desarchivado.

Consulta https://developers.google.com/android/guides/opensource para obtener información sobre cómo incluir avisos de código abierto.

Autenticación del SDK de consumidor

El SDK del consumidor proporciona autenticación mediante tokens web JSON. Un token web JSON (JWT) es un token de acceso basado en JSON que proporciona una o más reclamaciones sobre un servicio. Por ejemplo, un servidor podría generar un token con la reclamación “accedido como administrador” y proporcionársela a un cliente. Luego, el cliente podría usar ese token para demostrar que accedió como administrador.

El SDK del consumidor usa el token web JSON proporcionado por la aplicación para comunicarse con Fleet Engine. Consulta Autenticación y autorización de Flet Engine para obtener más información.

El token de autorización debe incluir una reclamación tripid:TRIP_ID en el encabezado authorization del token, en la que TRIP_ID es el ID de viaje. Esto le brinda al SDK del consumidor acceso a los detalles del viaje, incluida la posición del vehículo, la ruta y la hora de llegada estimada.

Devoluciones de llamada de token web JSON

El SDK de consumidor registra una devolución de llamada de token de autorización con la aplicación durante la inicialización. El SDK llama a la aplicación con el objetivo de obtener un token para todas las solicitudes de red que requieren autorización.

Te recomendamos enfáticamente que tus tokens de autorización de almacenamiento en caché para la implementación de devolución de llamada y que los actualices solo cuando haya transcurrido el tiempo expiry. Los tokens deben emitirse con un vencimiento de una hora.

La devolución de llamada del token de autorización especifica qué token de servicio se necesita para el servicio TripService. También proporciona el tripId requerido para el contexto.

En el siguiente ejemplo de código, se muestra cómo implementar una devolución de llamada de token de autorización.

Java

class JsonAuthTokenFactory implements AuthTokenFactory {

  private static final String TOKEN_URL =
      "https://yourauthserver.example/token";

  private static class CachedToken {
    String tokenValue;
    long expiryTimeMs;
    String tripId;
  }

  private CachedToken token;

  /*
  * This method is called on a background thread. Blocking is OK. However, be
  * aware that no information can be obtained from Fleet Engine until this
  * method returns.
  */
  @Override
  public String getToken(AuthTokenContext context) {
    // If there is no existing token or token has expired, go get a new one.
    String tripId = context.getTripId();
    if (tripId == null) {
      throw new RuntimeException("Trip ID is missing from AuthTokenContext");
    }
    if (token == null || System.currentTimeMillis() > token.expiryTimeMs ||
        !tripId.equals(token.tripId)) {
      token = fetchNewToken(tripId);
    }
    return token.tokenValue;
  }

  private static CachedToken fetchNewToken(String tripId) {
    String url = TOKEN_URL + "/" + tripId;
    CachedToken token = new CachedToken();

    try (Reader r = new InputStreamReader(new URL(url).openStream())) {
      com.google.gson.JsonObject obj
          = com.google.gson.JsonParser.parseReader(r).getAsJsonObject();

      token.tokenValue = obj.get("ServiceToken").getAsString();
      token.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 5 minutes from that time.
      */
      token.expiryTimeMs -= 5 * 60 * 1000;
    } catch (IOException e) {
      /*
      * It's OK to throw exceptions here. The error listeners will receive the
      * error thrown here.
      */
      throw new RuntimeException("Could not get auth token", e);
    }
    token.tripId = tripId;

    return token;
  }
}

Kotlin

class JsonAuthTokenFactory : AuthTokenFactory() {

  private var token: CachedToken? = null

  /*
  * This method is called on a background thread. Blocking is OK. However, be
  * aware that no information can be obtained from Fleet Engine until this
  * method returns.
  */
  override fun getToken(context: AuthTokenContext): String {
    // If there is no existing token or token has expired, go get a new one.
    val tripId = 
      context.getTripId() ?: 
        throw RuntimeException("Trip ID is missing from AuthTokenContext")

    if (token == null || System.currentTimeMillis() > token.expiryTimeMs ||
        tripId != token.tripId) {
      token = fetchNewToken(tripId)
    }

    return token.tokenValue
  }

  class CachedToken(
    var tokenValue: String? = "", 
    var expiryTimeMs: Long = 0,
    var tripId: String? = "",
  )

  private companion object {
    const val TOKEN_URL = "https://yourauthserver.example/token"

    fun fetchNewToken(tripId: String) {
      val url = "$TOKEN_URL/$tripId"
      val token = CachedToken()

      try {
        val reader = InputStreamReader(URL(url).openStream())

        reader.use {
          val obj = com.google.gson.JsonParser.parseReader(r).getAsJsonObject()

          token.tokenValue = obj.get("ServiceToken").getAsString()
          token.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 5 minutes from that time.
          */
          token.expiryTimeMs -= 5 * 60 * 1000
        }
      } catch (e: IOException) {
        /*
        * It's OK to throw exceptions here. The error listeners will receive the
        * error thrown here.
        */
        throw RuntimeException("Could not get auth token", e)
      }

      token.tripId = tripId

      return token
    }
  }
}

Cómo inicializar la API

Antes de seguir estos procedimientos, se supone que habilitaste los servicios adecuados y el SDK de consumidor.

Obtén la instancia ConsumerApi

Para usar el SDK de consumidor, tu app debe inicializar ConsumerApi de forma asíncrona. La API es un singleton. El método de inicialización toma un AuthTokenFactory. La fábrica genera tokens JWT nuevos para el usuario cuando es necesario.

El providerId es el ID de tu proyecto de Google Cloud. Consulta la Guía del usuario de Flet Engine para obtener más información sobre cómo crear el proyecto.

Tu app debe implementar AuthTokenFactory como se describe en Autenticación del SDK de consumidor.

Java

Task<ConsumerApi> consumerApiTask = ConsumerApi.initialize(
    this, "myProviderId", authTokenFactory);

consumerApiTask.addOnSuccessListener(
  consumerApi -> this.consumerApi = consumerApi);

Kotlin

val consumerApiTask =
  ConsumerApi.initialize(this, "myProviderId", authTokenFactory)

consumerApiTask?.addOnSuccessListener { consumerApi: ConsumerApi ->
  this@YourActivity.consumerApi = consumerApi
}

SDK de Maps y procesadores de mapas

La versión 2.x.x del SDK para consumidores es compatible con la versión 18.1.0 y posteriores del SDK de Maps para Android. En la siguiente tabla, se resume el procesador predeterminado por versión del SDK de Maps y la compatibilidad de ambos procesadores. Recomendamos usar el procesador más reciente; sin embargo, si necesitas usar el procesador heredado, puedes especificarlo explícitamente con MapsInitializer.initialize().

Versión del SDK de Maps Admite el procesador más reciente Admite el procesador heredado Procesador predeterminado
V18.1.0 y versiones anteriores Heredado*
V18.2.0 Más reciente

* Con el lanzamiento del nuevo procesador de Maps, el procesador más reciente será el predeterminado.

Agrega el SDK de Maps como dependencia

Gradle

Agrega lo siguiente a tu build.gradle:

dependencies {
  //...
  implementation "com.google.android.gms:play-services-maps:VERSION_NUMBER"
}

Maven

Agrega lo siguiente a tu pom.xml:

 <dependencies>
   ...
   <dependency>
     <groupId>com.google.android.gms</groupId>
     <artifactId>play-services-maps</artifactId>
     <version>18.1.0</version>
   </dependency>
 </dependencies>

Inicializa el SDK de Maps antes de inicializar el SDK para consumidores

En tu clase Application o Activity de inicio, llama a MapsInitializer.initialize() y espera el resultado de la solicitud del procesador antes de inicializar el SDK de consumidor.

java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  initViews();

  MapsInitializer.initialize(getApplicationContext(), Renderer.LATEST,
      new OnMapsSdkInitializedCallback() {
        @Override
        public void onMapsSdkInitialized(Renderer renderer) {
          switch (renderer) {
            case LATEST:
              Log.i("maps_renderer", "LATEST renderer");
              break;
            case LEGACY:
              Log.i("maps_renderer", "LEGACY renderer");
              break;
          }

          initializeConsumerSdk();
        }
      });
}

Kotlin

fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.main)
  initViews()

  MapsInitializer.initialize(
    getApplicationContext(), Renderer.LATEST,
    object : OnMapsSdkInitializedCallback() {
      fun onMapsSdkInitialized(renderer: Renderer?) {
        when (renderer) {
          LATEST -> Log.i("maps_renderer", "LATEST renderer")
          LEGACY -> Log.i("maps_renderer", "LEGACY renderer")
        }
        initializeConsumerSdk()
      }
    })
  }

Crea la interfaz de usuario

Puedes usar ConsumerMapFragment o ConsumerMapView para crear la interfaz de usuario de tu aplicación. ConsumerMapFragment te permite definir tu mapa usando una Fragment, mientras que ConsumerMapView te permite utilizar un View. La función de transporte privado con conductor es la misma en ConsumerMapView y ConsumerMapFragment, por lo que puedes elegir una en función de si View o Fragment son mejores para tu aplicación.

Se agregó compatibilidad con el nivel de API 19 (KitKat) y elementos de diseño vectoriales.

Si el diseño de tu app requiere compatibilidad con dispositivos de API 19 (KitKat) y elementos de diseño vectoriales, agrega el siguiente código a tu Activity. Este código extiende AppCompatActivity para usar los elementos de diseño vectoriales en el SDK del consumidor.

Java

// ...
import android.support.v7.app.AppCompatActivity;

// ...

public class ConsumerTestActivity extends AppCompatActivity {
  // ...
}

Kotlin

// ...
import android.support.v7.app.AppCompatActivity

// ...

class ConsumerTestActivity : AppCompatActivity() {
  // ...
}

Cómo agregar el fragmento o la vista del mapa

Crea el mapa para mostrar los viajes compartidos en un fragmento de Android o en una vista, que defines en el archivo en formato XML de diseño de tu aplicación (ubicado en /res/layout). Luego, el fragmento (o vista) proporciona acceso al mapa de viajes compartidos, al que tu app puede acceder y modificar. El mapa también proporciona un controlador para el ConsumerController, que permite que tu app controle y personalice la experiencia de compartir viajes.

Mapa y controlador para compartir la exploración

Debes definir el mapa para compartir el recorrido como un fragmento (con ConsumerMapFragment) o como una vista (con ConsumerMapView), como se muestra en el siguiente ejemplo de código. El método onCreate() debería llamar a getConsumerGoogleMapAsync(callback), que muestra ConsumerGoogleMap de forma asíncrona en la devolución de llamada. Luego, usa el ConsumerGoogleMap para mostrar el recorrido compartido, que tu app puede actualizar según sea necesario.

ConsumerMapFragment

El fragmento se define en el archivo XML de diseño de tu aplicación, como se muestra en el siguiente ejemplo de código.

<fragment
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.google.android.libraries.mapsplatform.transportation.consumer.view.ConsumerMapFragment"
    android:id="@+id/consumer_map_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

La llamada a getConsumerGoogleMapAsync() debe provenir del método onCreate().

Java

public class SampleAppActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {

    // Find the ConsumerMapFragment.
    ConsumerMapFragment consumerMapFragment =
        (ConsumerMapFragment) fragmentManager.findFragmentById(R.id.consumer_map_fragment);

    // Initiate the callback that returns the map.
    if (consumerMapFragment != null) {
      consumerMapFragment.getConsumerGoogleMapAsync(
          new ConsumerMapReadyCallback() {
            // The map returned in the callback is used to access the ConsumerController.
            @Override
            public void onConsumerMapReady(@NonNull ConsumerGoogleMap consumerGoogleMap) {
              ConsumerController consumerController = consumerGoogleMap.getConsumerController();
            }
          });
    }
  }

}

Kotlin

class SampleAppActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    // Find the ConsumerMapFragment.
    val consumerMapFragment =
      fragmentManager.findFragmentById(R.id.consumer_map_fragment) as ConsumerMapFragment

    consumerMapFragment.getConsumerGoogleMapAsync(
      object : ConsumerMapReadyCallback() {
        override fun onConsumerMapReady(consumerGoogleMap: ConsumerGoogleMap) {
          val consumerController = consumerGoogleMap.getConsumerController()!!
        }
      }
    )
  }
}
ConsumerMapView

Se puede usar en un fragmento o en una actividad, como se define en tu archivo en formato XML.

<com.google.android.libraries.mapsplatform.transportation.consumer.view.ConsumerMapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/consumer_map_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

La llamada a getConsumerGoogleMapAsync() debe ser de onCreate(). Además del parámetro de devolución de llamada, requiere la actividad o el fragmento que los contiene, así como una GoogleMapOptions (que puede ser nula), que contenga los atributos de configuración del MapView. La clase base de la actividad o el fragmento debe ser una FragmentActivity o una Fragment de compatibilidad (respectivamente), ya que proporcionan acceso a su ciclo de vida.

Java

public class SampleAppActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ConsumerMapView mapView = findViewById(R.id.consumer_map_view);

    if (mapView != null) {
      mapView.getConsumerGoogleMapAsync(
          new ConsumerMapReadyCallback() {
            // The map returned in the callback is used to access the ConsumerController.
            @Override
            public void onConsumerMapReady(@NonNull ConsumerGoogleMap consumerGoogleMap) {
              ConsumerController consumerController = consumerGoogleMap.getConsumerController();
            }
          }, this, null);
    }
  }

}

Kotlin

class SampleAppActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    val mapView = findViewById(R.id.consumer_map_view) as ConsumerMapView

    mapView.getConsumerGoogleMapAsync(
      object : ConsumerMapReadyCallback() {
        // The map returned in the callback is used to access the ConsumerController.
        override fun onConsumerMapReady(consumerGoogleMap: ConsumerGoogleMap) {
          val consumerController = consumerGoogleMap.getConsumerController()!!
        }
      },
      /* fragmentActivity= */ this,
      /* googleMapOptions= */ null,
    )
  }
}

Un MapView en un fragmento es el mismo que en el ejemplo anterior para MapView en una actividad, con la excepción de que el fragmento aumenta el diseño que incluye el MapView en el método onCreateView() del fragmento.

Java

public class MapViewInFragment extends Fragment {

  @Override
  public View onCreateView(
      @NonNull LayoutInflater layoutInflater,
      @Nullable ViewGroup viewGroup,
      @Nullable Bundle bundle) {
    return layoutInflater.inflate(R.layout.consumer_map_view, viewGroup, false);
  }

}

Kotlin

class MapViewInFragment : Fragment() {
  override fun onCreateView(
    layoutInflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View {
    return layoutInflater.inflate(R.layout.consumer_map_view, viewGroup, false)
  }
}

Cómo ajustar el zoom de la cámara para enfocar un viaje

El botón Mi ubicación predeterminado integrado en el SDK de Maps centra la cámara en la ubicación del dispositivo.

Si hay una sesión activa de Viajes compartidos, te recomendamos que centres la cámara para centrarte en el viaje en lugar de en la ubicación del dispositivo.

Solución integrada del SDK de consumidor para Android: AutoCamera

Para que puedas enfocarte en el recorrido en lugar de la ubicación del dispositivo, el SDK del consumidor proporciona una función de Cámara automática que está habilitada de forma predeterminada. La cámara se acerca para enfocarse en la ruta de viaje compartido y en el siguiente punto de referencia del viaje.

AutoCamera

Cómo personalizar el comportamiento de la cámara

Si necesitas más control del comportamiento de la cámara, puedes inhabilitar o habilitar la cámara automática con ConsumerController.setAutoCameraEnabled().

ConsumerController.getCameraUpdate() muestra los límites de cámara recomendados en ese momento. Luego, puedes proporcionar este CameraUpdate como argumento para GoogleMap.moveCamera() o GoogleMap.animateCamera().

Accede a mapas y transporte compartido

Para admitir el transporte compartido y la interacción con el mapa en tu aplicación, debes tener acceso a ConsumerGoogleMap y ConsumerController. ConsumerMapFragment y ConsumerMapView muestran ConsumerGoogleMap de forma asíncrona en ConsumerMapReadyCallback. ConsumerGoogleMap muestra ConsumerController de getConsumerController(). Puedes acceder a ConsumerGoogleMap y ConsumerController de la siguiente manera.

Java

private ConsumerGoogleMap consumerGoogleMap;
private ConsumerController consumerController;
private ConsumerMapView consumerMapView;

consumerMapView.getConsumerGoogleMapAsync(
    new ConsumerMapReadyCallback() {
      @Override
      public void onConsumerMapReady(@NonNull ConsumerGoogleMap consumerMap) {
        consumerGoogleMap = consumerMap;
        consumerController = consumerMap.getConsumerController();
      }
    },
    this, null);

Kotlin

var consumerGoogleMap: ConsumerGoogleMap
var consumerController: ConsumerController
val consumerMapView = findViewById(R.id.consumer_map_view) as ConsumerMapView

consumerMapView.getConsumerGoogleMapAsync(
  object : ConsumerMapReadyCallback() {
    override fun onConsumerMapReady(consumerMap: ConsumerGoogleMap) {
      consumerGoogleMap = consumerMap
      consumerController = consumerMap.getConsumerController()
    },
    /* fragmentActivity= */ this,
    /* googleMapOptions= */ null,
  }
)

ConsumerGoogleMap

ConsumerGoogleMap es una clase wrapper para la clase GoogleMap. Le brinda a tu app la capacidad de interactuar con el mapa mediante una API equivalente a GoogleMap. El uso del mapa del consumidor permite que tu app y el transporte compartido interactúen sin problemas con el mismo GoogleMap subyacente. Por ejemplo, GoogleMap solo permite un único registro de devolución de llamada, pero ConsumerGoogleMap admite devoluciones de llamada registradas duales. Estas devoluciones de llamada permiten que tu app y el servicio de transporte compartido registren devoluciones de llamada que se llaman de forma secuencial.

ConsumerController

ConsumerController proporciona acceso a la función de transporte compartido, como la supervisión de viajes, el control del estado de los viajes y la configuración de ubicaciones.

Cómo configurar la opción para compartir viajes

Después de que el backend haya encontrado a un consumidor con un vehículo, usa JourneySharingSession para iniciar la interfaz de usuario de uso compartido del recorrido. El viaje compartido muestra la ubicación y la ruta del vehículo emparejado. Después de implementar el SDK en tu app, puedes agregar la funcionalidad para supervisar viajes, detectar actualizaciones y controlar errores. En los siguientes procedimientos, se supone que los servicios de backend están implementados y que tus servicios para correlacionar a los consumidores con vehículos están operativos.

  1. Registra un objeto de escucha en un objeto TripModel para obtener detalles sobre el viaje, como la hora de llegada estimada (ETA) y la distancia que el vehículo debe recorrer antes de la llegada.

    Java

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    String tripName = ...;
    TripModelManager tripModelManager = consumerApi.getTripModelManager();
    TripModel tripModel = tripModelManager.getTripModel(tripName);
    
    // Create a JourneySharingSession instance based on the TripModel.
    JourneySharingSession session = JourneySharingSession.createInstance(tripModel);
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session);
    
    // Register for trip update events.
    tripModel.registerTripCallback(new TripModelCallback() {
      @Override
      public void onTripETAToNextWaypointUpdated(
          TripInfo tripInfo, @Nullable Long timestampMillis) {
        // ...
      }
    
      @Override
      public void onTripActiveRouteRemainingDistanceUpdated(
          TripInfo tripInfo, @Nullable Integer distanceMeters) {
        // ...
      }
    
      // ...
    });
    

    Kotlin

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    val tripName = "tripName"
    val tripModelManager = consumerApi.getTripModelManager()
    val tripModel = tripModelManager.getTripModel(tripName)
    
    // Create a JourneySharingSession instance based on the TripModel.
    val session = JourneySharingSession.createInstance(tripModel)
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session)
    
    // Register for trip update events.
    tripModel.registerTripCallback(
      object : TripModelCallback() {
        override fun onTripETAToNextWaypointUpdated(
          tripInfo: TripInfo,
          timestampMillis: Long?,
        ) {
          // ...
        }
    
        override fun onTripActiveRouteRemainingDistanceUpdated(
          tripInfo: TripInfo,
          distanceMeters: Int?,
        ) {
          // ...
        }
    
      // ...
    })
    
  2. Configura tu viaje con TripModelOptions.

    Java

    // Set refresh interval to 2 seconds.
    TripModelOptions tripOptions =
        TripModelOptions.builder().setRefreshIntervalMillis(2000).build();
    tripModel.setTripModelOptions(tripOptions);
    

    Kotlin

    // Set refresh interval to 2 seconds.
    val tripOptions = TripModelOptions.builder().setRefreshIntervalMillis(2000).build()
    tripModel.setTripModelOptions(tripOptions)
    

Dejar de compartir el viaje

Asegúrate de dejar de compartir el recorrido cuando ya no sea necesario, como cuando se destruye la actividad del host. Dejar de compartir el recorrido también detiene las solicitudes de red a Fleet Engine y evita las fugas de memoria.

En el siguiente código de muestra, se muestra cómo dejar de compartir el recorrido.

Java

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

  @Override
  protected void onDestroy() {
    super.onDestroy();

    if (journeySharingSession != null) {
      journeySharingSession.stop();
    }
  }
}

Kotlin

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

Maneja errores de viajes

El método onTripRefreshError muestra errores que ocurren durante la supervisión de viajes. La asignación de errores del SDK del consumidor sigue los mismos lineamientos de HTTP/RPC que se establecieron para Google Cloud Platform. Estos son algunos de los errores comunes que surgen durante la supervisión de viajes:

HTTP RPC Descripción
400 INVALID_ARGUMENT El cliente especificó un nombre de viaje no válido. El nombre del viaje debe seguir el formato providers/{provider_id}/trips/{trip_id}. El provider_id debe ser el ID del proyecto de Cloud que pertenece al proveedor de servicios.
401 UNAUTHENTICATED La solicitud no se autenticó debido a un token JWT no válido. Este error se producirá si el token JWT se firma sin un ID de viaje o si el token JWT caducó.
403 PERMISSION_DENIED El cliente no tiene permisos suficientes. Este error ocurre si el token JWT no es válido, el cliente no tiene permiso o la API no está habilitada para el proyecto del cliente. Es posible que falte el token JWT o que el token se firme con un ID de viaje que no coincide con el ID de viaje solicitado.
429 RESOURCE_EXHAUSTED La cuota de recursos es de cero o la tasa de tráfico excede el límite.
503 UNAVAILABLE Servicio no disponible. Por lo general, el servidor no funciona.
504 DEADLINE_EXCEEDED Se excedió el plazo de la solicitud. Esto sucederá solo si el llamador establece una fecha límite que es más corta que la fecha límite predeterminada del método (es decir, si el plazo solicitado no es suficiente para que el servidor procese la solicitud) y la solicitud no finalizó dentro del plazo.

Para obtener más información, consulta Manejo de errores del SDK de consumidor.