Consumer SDK for Android のスタートガイド

Consumer SDK を使用して、オンデマンド配車および配達ソリューションのバックエンド サービスと統合された基本的な一般ユーザー向けアプリを構築して実行できます。有効なルートの表示、ルート更新情報への応答、ルートエラーの処理が可能な Trip and Order Progress アプリを作成できます。

Consumer SDK はモジュラー アーキテクチャであるため、特定のアプリに使用する API の部分を、独自の API、Fleet Engine が提供するバックエンド サービス、Google Maps Platform のその他の API と統合できます。

最小システム要件

モバイル デバイスに Android 6.0(API レベル 23)以降が搭載されている必要があります。

Maven の構成

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

Project Configuration

Consumer SDK for Android を使用するには、アプリで minSdkVersion 23 以降をターゲットに設定する必要があります。

Consumer SDK でビルドしたアプリを実行するには、Android デバイスに Google Play 開発者サービスがインストールされている必要があります。

開発プロジェクトを設定する

Google Cloud コンソールで開発プロジェクトをセットアップし、プロジェクトの API キーを取得するには:

  1. Consumer SDK で使用する新しい Google Cloud Console プロジェクトを作成するか、既存のプロジェクトを選択します。新しいプロジェクトが Google Cloud コンソールに表示されるまで数分待ちます。

  2. デモアプリを実行するには、プロジェクトが Maps SDK for Android にアクセスできる必要があります。Google Cloud コンソールで [API とサービス] > [ライブラリ] を選択し、Maps SDK for Android を検索して有効にします。

  3. [API とサービス] > [認証情報] > [認証情報を作成] > [API キー] を選択して、プロジェクトの API キーを取得します。API キーの取得について詳しくは、API キーを取得するをご覧ください。

アプリに Consumer SDK を追加する

Consumer SDK は非公開の Maven リポジトリから入手できます。リポジトリには、SDK のプロジェクト オブジェクト モデル(.pom)ファイルと Javadocs が含まれています。Consumer 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>
    

アプリに API キーを追加する

Consumer SDK をアプリに追加したら、アプリに API キーを追加します。開発プロジェクトを設定したときに取得したプロジェクト API キーを使用する必要があります。

このセクションでは、アプリから安全に参照できるように API キーを保存する方法について説明します。API キーは、バージョン管理システムにはチェックインしないでください。このファイルはプロジェクトのルート ディレクトリにある local.properties ファイルに保存する必要があります。local.properties ファイルの詳細については、Gradle プロパティ ファイルをご覧ください。

このタスクを効率化するには、Android 用 Secrets Gradle プラグインを使用します。

プラグインをインストールして API キーを保存するには:

  1. ルートレベルの build.gradle ファイルを開き、buildscriptdependencies 要素に次のコードを追加します。

    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 を使用する場合は、アプリの法的通知のセクションにアトリビューション テキストとオープンソース ライセンスを含める必要があります。帰属情報は、独立したメニュー項目として、または [About] メニュー項目の一部として含めることをおすすめします。

ライセンス情報は、アーカイブ解除された AAR ファイルの「third_party_licenses.txt」ファイルで確認できます。

オープンソースに関する通知を含める方法については、https://developers.google.com/android/guides/opensource をご覧ください。

コンシューマ SDK 認証

Consumer SDK は、JSON ウェブトークンを使用した認証を提供します。JSON Web Token(JWT)は、サービスに 1 つ以上のクレームを提供する JSON ベースのアクセス トークンです。たとえば、サーバーが「管理者としてログイン」というクレームを含むトークンを生成し、それをクライアントに提供できます。クライアントはそのトークンを使用して、管理者としてログインしていることを証明できます。

Consumer SDK は、アプリケーションから提供される JSON Web Token を使用して Fleet Engine と通信します。詳細については、Fleet Engine の認証と認可をご覧ください。

認証トークンでは、トークンの authorization ヘッダーに tripid:TRIP_ID クレームを含める必要があります。ここで、TRIP_ID はルート ID です。これにより、Consumer SDK がルートの詳細(車両の位置、経路、到着予定時刻など)にアクセスできるようになります。

JSON Web Token コールバック

コンシューマ SDK は、初期化中にアプリケーションに認証トークンのコールバックを登録します。SDK はアプリケーションを呼び出し、承認が必要なすべてのネットワーク リクエストのトークンを取得します。

コールバックの実装で認可トークンをキャッシュに保存し、expiry 時間が経過したときにのみ更新することを強くおすすめします。トークンは 1 時間の有効期限で発行する必要があります。

認証トークン コールバックは、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 を初期化する

以下の手順を行う前に、適切なサービスと Consumer SDK が有効になっていることを前提としています。

ConsumerApi インスタンスを取得する

Consumer SDK を使用するには、アプリで ConsumerApi を非同期で初期化する必要があります。この API はシングルトンです。初期化メソッドは AuthTokenFactory を受け取ります。必要に応じて、ファクトリによってユーザーの新しい JWT トークンが生成されます。

providerId は、Google Cloud プロジェクトのプロジェクト ID です。プロジェクトの作成の詳細については、Fleet Engine ユーザーガイドをご覧ください。

アプリでは、コンシューマ SDK 認証の説明に沿って AuthTokenFactory を実装する必要があります。

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 を初期化して優先レンダラをリクエストする

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

Consumer SDK を初期化する前に Maps 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()
      }
    })
  }

ユーザー インターフェースを作成する

ConsumerMapFragment または ConsumerMapView を使用して、アプリケーションのユーザー インターフェースを作成できます。ConsumerMapFragment では Fragment を使用して地図を定義できますが、ConsumerMapView では View を使用できます。ライドシェアリング機能は ConsumerMapViewConsumerMapFragment の両方で同じであるため、ViewFragment のどちらがアプリケーションに適しているかに応じて選択してください。

API 19(KitKat)とベクター型ドローアブルのサポートを追加

アプリの設計で API 19(KitKat)デバイスとベクター型ドローアブルのサポートが必要な場合は、次のコードをアクティビティに追加します。このコードは、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() {
  // ...
}

地図のフラグメントまたはビューを追加する

Android フラグメントまたはビューのいずれかに、ジャーニーの共有を表示するためのマップを作成します。このマップは、アプリのレイアウト XML ファイル(/res/layout にあります)で定義します。フラグメント(またはビュー)は、アプリがアクセスおよび変更できる、ジャーニー共有マップへのアクセスを提供します。また、地図には ConsumerController へのハンドルも用意されており、アプリでジャーニーの共有エクスペリエンスを制御、カスタマイズできます。

移動経路の共有地図とコントローラ

次のコード例に示すように、ジャーニー共有マップをフラグメント(ConsumerMapFragment を使用)またはビュー(ConsumerMapView を使用)として定義します。次に、onCreate() メソッドは getConsumerGoogleMapAsync(callback) を呼び出す必要があります。これにより、コールバックで ConsumerGoogleMap が非同期で返されます。次に、ConsumerGoogleMap を使用して移動経路の共有を表示します。これはアプリで必要に応じて更新できます。

ConsumerMapFragment

次のサンプルコードのように、アプリ レイアウト XML ファイルでフラグメントを定義します。

<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

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() から行う必要があります。コールバック パラメータに加えて、それを含むアクティビティやフラグメント、および MapView の構成属性を含む GoogleMapOptions(null にすることもできます)が必要です。アクティビティまたはフラグメントの基本クラスは、ライフサイクルへのアクセスを提供するため、それぞれ 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,
    )
  }
}

フラグメント内の MapView は、フラグメントがフラグメントの onCreateView() メソッド内の MapView を含むレイアウトをインフレートする点を除き、アクティビティの 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 に組み込まれているデフォルトの現在地ボタンでは、カメラの位置がデバイスの位置に合わせられます。

移動経路の共有セッションがアクティブな場合は、デバイスの位置情報ではなく、移動にカメラを集中させることをおすすめします。

Consumer SDK for Android 組み込みソリューション: AutoCamera

デバイスの位置情報ではなくジャーニーに集中できるように、Consumer SDK には、デフォルトで有効になっている AutoCamera 機能が用意されています。ジャーニーを共有するルートと次のルートの地点にフォーカスするようにカメラがズームします。

AutoCamera

カメラの動作のカスタマイズ

カメラの動作をより細かく制御する必要がある場合は、ConsumerController.setAutoCameraEnabled() を使用して自動カメラを無効または有効にできます。

ConsumerController.getCameraUpdate() は、その時点で推奨されるカメラの境界を返します。この CameraUpdate を引数として GoogleMap.moveCamera() または GoogleMap.animateCamera() に指定できます。

ライドシェアリングと地図にアクセス

アプリでライドシェアリングと地図の操作をサポートするには、ConsumerGoogleMapConsumerController にアクセスする必要があります。ConsumerMapFragmentConsumerMapView はどちらも非同期で ConsumerMapReadyCallbackConsumerGoogleMap を返します。ConsumerGoogleMapgetConsumerController() から 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

ConsumerGoogleMap は、GoogleMap クラスのラッパークラスです。これにより、アプリは GoogleMap と同等の API を使用して地図を操作できるようになります。一般ユーザー向けマップを使用すると、アプリとライドシェアリングで、基盤となる同じ GoogleMap をシームレスに操作できます。たとえば、GoogleMap は 1 つのコールバック登録のみを許可しますが、ConsumerGoogleMap はデュアル登録済みコールバックをサポートします。これらのコールバックにより、アプリとライドシェアリングは、順次呼び出されるコールバックを登録できます。

ConsumerController

ConsumerController を使用すると、ルートのモニタリング、ルート ステータスの管理、場所の設定など、ライドシェアリング機能にアクセスできます。

ジャーニーの共有を設定する

バックエンドでユーザーと車両がマッチングされたら、JourneySharingSession を使用してジャーニー共有ユーザー インターフェースを開始します。移動経路の共有には、一致した車両の位置情報とルートが表示されます。この SDK をアプリに実装すると、ルートのモニタリング、更新情報のリッスン、エラーの処理を行う機能を追加できます。次の手順では、バックエンド サービスが導入され、ユーザーと車両を照合するサービスが稼働していることを前提としています。

  1. TripModel オブジェクトにリスナーを登録して、到着予定時刻(ETA)や到着前に車両が移動するのに必要な距離など、ルートの詳細を取得します。

    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 へのネットワーク リクエストも停止し、メモリリークを防止できます。

次のサンプルコードは、乗車経路の共有を停止する方法を示しています。

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 のエラー処理をご覧ください。