Android でルートをフォローする

プラットフォームを選択: Android iOS JavaScript

ルートを追跡すると、適切な車両の位置情報がコンシューマ アプリに表示されます。これを行うには、アプリでルートの追跡を開始し、ルートの進行状況を更新し、ルートの完了時にルートの追跡を停止する必要があります。

このドキュメントでは、そのプロセスの仕組みについて説明します。

始める前に

次のものが設定されていることを確認します。

  • コンシューマ アプリのバックエンド サービスが設定され、コンシューマと車両を照合するサービスが動作している。

  • アプリに地図を設定している。

ルート案内のフォローを開始する

バックエンド サーバーがコンシューマと車両を照合したら、JourneySharingSession を使用してルートの追跡を開始します。

次のサンプルコードは、ビューの読み込み後にルートのフォローを開始する方法を示しています。

Java

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Create a TripModel instance to listen for 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) {
        // ...
      }

      // ...
    });
  }

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

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

Kotlin

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Create a TripModel instance to listen for 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?,
        ) {
          // ...
        }

      // ...
    })
  }

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

ルートの進行状況を更新する

車両が到着するまでに移動する距離や到着予定時刻など、ルートの進行状況の詳細を更新するには、次の例に示すように、アプリでリスナーを登録して構成する必要があります。

  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)
    

旅行のフォローを停止する

ドライバーがバックエンドでルートを「完了」としてマークした場合など、ルートの追跡が不要になったときに、アプリがルートの追跡を停止するようにしてください。ルートの共有を停止すると、Fleet Engine への不要なネットワーク リクエストを回避し、メモリリークを防ぐことができます。

次のサンプルコードに示すように、JourneySharingSession を使用してルートの追跡を停止します。

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 メソッドは、ルート モニタリング中に発生したエラーを表示します。エラー メッセージは Google Cloud エラー標準に準拠しています。エラー メッセージの詳細な定義とすべてのエラーコードについては、Google Cloud エラーのドキュメントをご覧ください。

ルート モニタリング中に発生する可能性のある一般的なエラーは次のとおりです。

HTTP RPC 説明
400 INVALID_ARGUMENT クライアントが無効なルート名を指定しました。ルート名は providers/{provider_id}/trips/{trip_id} の形式にする必要があります。provider_id は、サービス プロバイダが所有する Cloud プロジェクトの ID にする必要があります。
401 UNAUTHENTICATED このエラーは、有効な認証情報がない場合に発生します。たとえば、JWT トークンがルート ID なしで署名されている場合や、JWT トークンの有効期限が切れている場合などです。
403 PERMISSION_DENIED このエラーは、クライアントに十分な権限がない(コンシューマ ロールを持つユーザーが updateTrip を呼び出そうとしている場合など)、JWT トークンが無効である場合、またはクライアント プロジェクトで API が有効になっていない場合に発生します。JWT トークンがないか、リクエストされたルート ID と一致しないルート ID でトークンが署名されている可能性があります。
429 RESOURCE_EXHAUSTED リソース割り当てがゼロであるか、トラフィックのレートが上限を超えています。
503 UNAVAILABLE サービス利用不可。通常、サーバーがダウンしています。
504 DEADLINE_EXCEEDED リクエスト期限を超えました。このエラーは、呼び出し元がメソッドのデフォルト期限よりも短い期限を設定し(つまり、要求された期限はサーバーがリクエストを処理するのに十分ではない)、リクエストがその期限内に完了しなかった場合にのみ発生します。

Consumer SDK エラーを処理する

Consumer SDK は、コールバック メカニズムを使用して、ルートの更新エラーをコンシューマ アプリに送信します。コールバック パラメータは、プラットフォーム固有の戻り値の型です(Android では TripUpdateError、iOS では NSError)。

ステータス コードを抽出する

コールバックに渡されるエラーは通常 gRPC エラーであり、ステータス コードの形式で追加情報を抽出することもできます。ステータス コードの完全なリストについては、ステータス コードと gRPC での使用をご覧ください。

Java

onTripUpdateError() から返された TripUpdateError から、エラーの詳細を示す gRPC ステータス コードを抽出できます。

// Called when there is a trip update error.
@Override
public void onTripUpdateError(TripInfo tripInfo, TripUpdateError error) {
  Status.Code code = error.getStatusCode();
}

Kotlin

onTripUpdateError() から返された TripUpdateError から、エラーの詳細を示す gRPC ステータス コードを抽出できます。

// Called when there is a trip update error.
override fun onTripUpdateError(tripInfo: TripInfo, error: TripUpdateError) {
  val code = error.getStatusCode()
}

ステータス コードの解釈

ステータス コードは、サーバーおよびネットワーク関連のエラーとクライアントサイド エラーの 2 種類のエラーに対応しています。

サーバーおよびネットワークのエラー

次のステータス コードはネットワーク エラーまたはサーバー エラーであり、解決するための対応は必要ありません。Consumer SDK は自動的に復元します。

ステータス コード説明
ABORTED サーバーがレスポンスを送信しなくなった。これは通常、サーバーの問題が原因で発生します。
CANCELLED サーバーが送信レスポンスを終了しました。これは通常、
アプリがバックグラウンドに送信されたとき、または
コンシューマ アプリの状態が変更されたときに発生します。
INTERRUPTED
DEADLINE_EXCEEDED サーバーの応答に時間がかかりすぎました。
UNAVAILABLE サーバーが利用できなかった。これは通常、ネットワークの問題が原因で発生します。

クライアントエラー

次のステータス コードはクライアント エラーであり、解決するには対応する必要があります。ユーザー SDK は、ルートの共有を終了するまでルートの更新を再試行し続けますが、ユーザーが操作を行うまで復元されません。

ステータス コード説明
INVALID_ARGUMENT コンシューマ アプリで無効なルート名が指定されています。ルート名は providers/{provider_id}/trips/{trip_id} の形式にする必要があります。
NOT_FOUND 旅行が作成されなかった。
PERMISSION_DENIED コンシューマ アプリに十分な権限がありません。このエラーは、次の場合に発生します。
  • コンシューマ アプリに権限がない
  • Google Cloud コンソールで、プロジェクトで Consumer SDK が有効になっていません。
  • JWT トークンがないか、無効です。
  • JWT トークンが、リクエストされたルートとは異なるルート ID で署名されている。
RESOURCE_EXHAUSTED リソース割り当てがゼロであるか、トラフィック フローのレートが制限速度を超えている。
UNAUTHENTICATED JWT トークンが無効なため、リクエストの認証に失敗しました。このエラーは、JWT トークンがルート ID なしで署名されている場合、または JWT トークンの有効期限が切れている場合に発生します。