面向 Android 的 Consumer SDK 使用入门

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

由于使用方 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 或更高版本为目标平台。

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

设置您的开发项目

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

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

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

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

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

消费者 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 占位符替换为所需的使用方 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. 使用方 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 密钥

将使用方 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>

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

如果您在自己的应用中使用消费者 SDK,则必须在应用的法律声明部分包含提供方说明文本和开源许可。最好将提供方说明作为独立的菜单项或关于菜单项的一部分进行添加。

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

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

使用方 SDK 身份验证

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

使用方 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 实例

如需使用消费者 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.x.x 支持 Maps SDK for Android v18.1.0 及更高版本。下表总结了各 Maps SDK 版本的默认渲染程序以及这两种渲染程序的可支持情况。我们建议您使用最新版渲染程序,但如果您需要使用旧版渲染程序,则可以使用 MapsInitializer.initialize() 明确指定它。

Maps SDK 版本 支持最新版渲染程序 支持旧版渲染程序 默认渲染程序
V18.1.0 及更低版本 旧版*
V18.2.0 从新到旧

* 随着新版地图渲染程序的推出,系统将默认使用最新版渲染程序。

将 Maps SDK 添加为依赖项

Gradle

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

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

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,然后再初始化使用方 SDK

Application 或启动 Activity 类中,调用 MapsInitializer.initialize() 并等待渲染程序请求结果,然后再初始化使用方 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,以使用使用方 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" />

应从 onCreate() 方法调用 getConsumerGoogleMapAsync()

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 中异步返回 ConsumerGoogleMapConsumerGoogleMap 会从 getConsumerController() 返回 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 方法会显示行程监控期间发生的错误。使用方 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 错误处理