面向 Android 的 Consumer SDK 使用入门

您可以使用 Consumer SDK 构建并运行与按需行程和配送解决方案后端服务集成的基本消费者应用。您可以创建一个行程和订单进度应用,该应用可以显示进行中的行程、响应行程更新以及处理行程错误。

由于 Consumer SDK 采用模块化架构,因此您可以使用要用于特定应用的 API 部分,并将其与您自己的 API、Fleet Engine 提供的后端服务以及 Google Maps Platform 的其他 API 集成。

最低系统要求

移动设备必须搭载 Android 6.0(API 级别 23)或更高版本。

构建和依赖项配置

消费者 SDK 版本 1.99.0 及更高版本可通过 Google Maven 制品库获得。之前使用的私有代码库渠道已弃用。

Gradle

请将以下内容添加到 build.gradle 文件:

repositories {
    ...
    google()
}

Maven

请将以下内容添加到 pom.xml 文件:

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

项目配置

如需使用面向 Android 的消费者 SDK,您的应用必须以 minSdkVersion 23 或更高版本为目标平台。

如需运行使用 Consumer SDK 构建的应用,Android 设备必须安装 Google Play 服务

设置您的开发项目

如需在 Google Cloud 控制台上设置开发项目并获取该项目的 API 密钥,请执行以下操作:

  1. 创建新的 Google Cloud 控制台项目,或者选择一个现有项目,以便与 Consumer SDK 结合使用。等待几分钟,直到新项目显示在 Google Cloud 控制台上。

  2. 为了运行演示版应用,您的项目必须有权访问 Maps SDK for Android。在 Google Cloud 控制台中,依次选择 API 和服务 > 库,然后搜索并启用 Maps SDK for Android。

  3. 依次选择 API 和服务 > 凭据 > 创建凭据 > API 密钥,获取项目的 API 密钥。如需详细了解如何获取 API 密钥,请参阅获取 API 密钥

将消费者 SDK 添加到您的应用

Consumer SDK 可通过私有 Maven 制品库获得。代码库包含 SDK 的项目对象模型 (.pom) 文件和 Javadocs。如需将消费者 SDK 添加到您的应用中,请执行以下操作:

  1. 按照上一部分中的说明,设置您的环境以访问主机 Maven 制品库。

    如果您在 settings.gradle 中声明了集中式依赖项管理配置,请按如下方式将其停用。

    • 移除 settings.gradle 中的以下代码块:

      import org.gradle.api.initialization.resolve.RepositoriesMode
      dependencyResolutionManagement {
          repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
          repositories {
              google()
              mavenCentral()
          }
      }
      
  2. 将以下依赖项添加到您的 Gradle 或 Maven 配置中,将 VERSION_NUMBER 占位符替换为所需的 Consumer SDK 版本。

    Gradle

    将以下内容添加到 build.gradle 中:

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

    Maven

    将以下内容添加到 pom.xml 中:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-consumer</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  3. Consumer SDK 依赖于 Maps SDK。此依赖项的配置方式如下:如果未在 build 配置文件中明确定义 Maps SDK 版本(如下所示),则在发布新版 Maps SDK 时,消费者 SDK 将继续使用所支持的最低 Maps SDK 版本。

    Gradle

    将以下内容添加到 build.gradle 中:

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

    Maven

    将以下内容添加到 pom.xml 中:

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

向应用添加 API 密钥

将 Consumer SDK 添加到您的应用后,请将 API 密钥添加到您的应用。您必须使用在设置开发项目时获得的项目 API 密钥。

本部分介绍如何存储 API 密钥,以便您的应用可以更安全地引用该密钥。您不应将 API 密钥签入版本控制系统。它应该存储在项目根目录下的 local.properties 文件中。如需详细了解 local.properties 文件,请参阅 Gradle 属性文件

为了简化此任务,您可以使用 Android 版 Secrets Gradle 插件

如需安装此插件并存储您的 API 密钥,请执行以下操作:

  1. 打开根级 build.gradle 文件,并将以下代码添加到 buildscript 下的 dependencies 元素中。

    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. 打开应用级 build.gradle 文件,并将以下代码添加到 plugins 元素中。

    Groovy

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

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. 如果您使用 Android Studio,请将项目与 Gradle 同步

  4. 在项目级目录中打开 local.properties,然后添加以下代码。将 YOUR_API_KEY 替换为您的 API 密钥。

    MAPS_API_KEY=YOUR_API_KEY
    
  5. AndroidManifest.xml 文件中,定位到 com.google.android.geo.API_KEY 并按如下所示更新 android:value 属性:

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

以下示例显示了一个示例应用的完整清单:

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

在您的应用中添加必要的提供方说明

如果您在应用中使用 Consumer SDK,则必须在应用的法律声明部分包含提供方说明文本和开源许可。最好以独立菜单项的形式提供提供方说明,或将提供方说明作为关于菜单项的一部分提供。

许可信息可以在未归档的 AAR 文件中的“third_party_licenses.txt”文件中找到。

如需了解如何添加开源声明,请参阅 https://developers.google.com/android/guides/opensource

消费者 SDK 身份验证

Consumer SDK 使用 JSON Web 令牌进行身份验证。JSON Web 令牌 (JWT) 是一种基于 JSON 的访问令牌,可针对服务提供一个或多个声明。例如,服务器可以生成一个具有“以管理员身份登录”声明的令牌,并将该令牌提供给客户端。然后,客户端可以使用该令牌证明自己是以管理员身份登录的。

Consumer SDK 使用应用提供的 JSON Web 令牌与 Fleet Engine 通信。如需了解详情,请参阅舰队引擎身份验证和授权

授权令牌必须在令牌的 authorization 标头中添加 tripid:TRIP_ID 声明,其中 TRIP_ID 是行程 ID。这样,消费者 SDK 就可以访问行程详细信息,包括车辆位置、路线和预计到达时间。

JSON Web 令牌回调

消费者 SDK 在初始化期间向应用注册授权令牌回调。SDK 会调用应用,为所有需要授权的网络请求获取令牌。

我们强烈建议您的回调实现缓存授权令牌,并仅在 expiry 时间过后刷新这些令牌。令牌的有效期应该是一小时。

授权令牌回调指定 TripService 服务需要哪个服务令牌。它还为上下文提供了所需的 tripId

以下代码示例演示了如何实现授权令牌回调。

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

初始化 API

在执行这些步骤之前,假设您已启用相应服务和消费者 SDK。

获取 ConsumerApi 实例

如需使用 Consumer SDK,您的应用需要异步初始化 ConsumerApi。该 API 是一个单例。 初始化方法接受 AuthTokenFactory。必要时,工厂会为用户生成新的 JWT 令牌。

providerId 是您的 Google Cloud 项目的ID。如需详细了解如何创建项目,请参阅 Fleet Engine 用户指南

您的应用应实现 AuthTokenFactory,如消费者 SDK 身份验证中所述。

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
}

初始化 Maps SDK 以请求使用首选渲染程序

消费者 SDK v2.0.0 支持 Maps SDK for Android v18.1.0 及更高版本。它支持指定首选 Google 地图渲染程序的请求。如需了解详情,请参阅新版地图渲染程序(选择启用)

将 Maps SDK 添加为依赖项

Gradle

将以下内容添加到 build.gradle 中:

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

Maven

将以下内容添加到 pom.xml 中:

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

先初始化 Maps SDK,然后再初始化 Consumer SDK

Application 或启动 Activity 类中,调用 MapsInitializer.initialize() 并等待渲染程序请求结果,然后再初始化 Consumer SDK。

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()
      }
    })
  }

创建界面

您可以使用 ConsumerMapFragmentConsumerMapView 为您的应用创建界面。ConsumerMapFragment 可让您使用 Fragment 定义地图,而 ConsumerMapView 允许您使用 ViewConsumerMapViewConsumerMapFragment 中的拼车功能相同,因此您可以根据您的应用更适合使用 View 还是 Fragment 来选择其中一项。

添加了对 API 19 (KitKat) 和矢量可绘制对象的支持

如果您的应用设计需要支持 API 19 (KitKat) 设备和矢量可绘制对象,请将以下代码添加到您的 Activity 中。这些代码会扩展 AppCompatActivity,以使用 Consumer SDK 中的矢量可绘制对象。

Java

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

// ...

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

Kotlin

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

// ...

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

添加地图 fragment 或视图

您可以创建用于在 Android fragment 或视图(您在应用布局 XML 文件(位于 /res/layout)中定义)中定义的行程共享地图。然后,fragment(或视图)会提供对行程共享地图的访问权限,您的应用可以访问和修改该地图。地图还提供了 ConsumerController 的句柄,可让您的应用控制和自定义行程共享体验。

行程共享地图和控制器

您可以将旅程共享地图定义为 fragment(使用 ConsumerMapFragment)或视图(使用 ConsumerMapView),如以下代码示例所示。然后,您的 onCreate() 方法应调用 getConsumerGoogleMapAsync(callback),该方法会在回调中异步返回 ConsumerGoogleMap。然后,您可以使用 ConsumerGoogleMap 显示行程分享,并且可以根据应用需要对其进行更新。

ConsumerMapFragment

您可以在应用布局 XML 文件中定义 fragment,如以下代码示例所示。

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

getConsumerGoogleMapAsync() 的调用应来自 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

该视图可以在 fragment 或 activity(如 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" />

getConsumerGoogleMapAsync() 的调用应来自 onCreate()。除了回调参数之外,它还需要包含的 activity 或 fragment,以及包含 MapView 配置属性的 GoogleMapOptions(可以为 null)。activity 或 fragment 基类分别必须是 FragmentActivity 或支持 Fragment,因为它们提供对其生命周期的访问权限。

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,
    )
  }
}

fragment 中的 MapView 与上面为 activity 中的 MapView 的示例相同,只不过 fragment 会膨胀 fragment onCreateView() 方法中包含 MapView 的布局。

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

调整相机缩放以聚焦于旅程

Maps SDK 中内置的默认“我的位置”按钮会将相机置于设备所在位置的中心。

如果存在正在进行的行程分享会话,您可能需要将摄像头居中,以便聚焦于行程而不是设备位置。

适用于 Android 的消费类 SDK 内置解决方案:AutoCamera

为了让您专注于历程而非设备位置,消费者 SDK 提供了 AutoCamera 功能,该功能默认处于启用状态。相机会进行缩放,以聚焦于共享行程路线和下一个行程航点。

AutoCamera

自定义相机行为

如果您需要更好地控制相机行为,可以使用 ConsumerController.setAutoCameraEnabled() 停用或启用自动相机。

ConsumerController.getCameraUpdate() 随即返回推荐的镜头边界。然后,您可以将此 CameraUpdate 作为参数提供给 GoogleMap.moveCamera()GoogleMap.animateCamera()

使用拼车和查看地图

如需在您的应用中支持拼车和地图互动,您需要访问 ConsumerGoogleMapConsumerControllerConsumerMapFragmentConsumerMapView 都会在 ConsumerMapReadyCallback 中异步返回 ConsumerGoogleMapConsumerGoogleMapgetConsumerController() 返回 ConsumerController。您可以按如下方式访问 ConsumerGoogleMapConsumerController

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

ConsumerGoogleMapGoogleMap 类的封装容器类。它可让您的应用使用与 GoogleMap 等效的 API 与地图进行交互。通过使用消费者地图,您的应用和拼车服务可以与同一底层 GoogleMap 无缝互动。例如,GoogleMap 仅允许单次回调注册,但 ConsumerGoogleMap 支持双注册的回调。 这些回调允许您的应用和拼车服务注册依序调用的回调。

ConsumerController

ConsumerController 可用于使用拼车功能,例如监控行程、控制行程状态和设置位置。

设置行程共享

在后端将消费者与车辆匹配后,使用 JourneySharingSession 启动行程共享界面。行程共享功能会显示匹配的车辆位置和路线。在应用中实现 SDK 后,您可以添加用于监控行程、监听更新和处理错误的功能。以下过程假定后端服务已就绪,并且用于将消费者与车辆匹配的服务正常运行。

  1. TripModel 对象上注册监听器,以获取有关行程的详细信息,例如预计到达时间和车辆在到达之前需要行驶的距离。

    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. 使用“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)
    

停止共享行程

确保在不再需要历程时(例如在宿主 activity 被销毁时)停止共享历程。停止历程共享还会停止对 Fleet Engine 的网络请求,并防止内存泄漏。

以下示例代码演示了如何停止共享行程。

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()
  }
}

处理行程错误

onTripRefreshError 方法会显示行程监控期间发生的错误。Consumer SDK 错误的映射遵循为 Google Cloud Platform 制定的相同 HTTP/RPC 准则。行程监控期间出现的常见错误包括:

HTTP RPC 说明
400 INVALID_ARGUMENT 客户指定了无效的行程名称。行程名称必须遵循格式 providers/{provider_id}/trips/{trip_id}provider_id 必须是服务提供商所拥有的 Cloud 项目的 ID。
401 未经身份验证 由于 JWT 令牌无效,请求未通过身份验证。如果对 JWT 令牌进行签名时没有行程 ID 或 JWT 令牌过期,则会出现此错误。
403 PERMISSION_DENIED 客户端权限不足。如果 JWT 令牌无效、客户端没有权限或者客户端项目未启用 API,则会出现此错误。JWT 令牌可能缺失,或者令牌使用的行程 ID 与请求的行程 ID 不匹配。
429 RESOURCE_EXHAUSTED 资源配额为零或流量速率超过限制。
503 不可用 服务不可用。通常情况下,服务器会关闭。
504 DEADLINE_EXCEEDED 超出请求时限。仅当调用方设置的截止时间短于该方法的默认截止时间(即请求的截止时间不足以让服务器处理请求)且请求未在该截止时间内完成时,才会发生这种情况。

如需了解详情,请参阅消费者 SDK 错误处理