オンデマンド配車および配達ソリューションは現在、一部のパートナー様のみご利用いただけます。

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

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

Driver SDK を使用すると、Trip and Order Progress アプリに高度なナビゲーションとトラッキングを提供できます。Driver SDK は On-demand Rides and Deliveries Solution Fleet Engine に車両の位置情報とタスクの更新を提供します。

Driver SDK は、Fleet Engine サービスとカスタム サービスが車両の位置情報と状態を認識します。たとえば、車両が ONLINE または OFFLINE の場合、ルートの進行に伴って車両の位置が変わります。

最小システム要件

モバイル デバイスが Android 5.0(API レベル 21)以降を実行している。

Prerequisites

輸送と物流の Android SDK は、Artifact Registry Maven リポジトリに公開されます。リポジトリには、SDK のプロジェクト オブジェクト モデル(.pom)ファイルとオフライン Javadocs が含まれています。

アクセス権の取得

Google Workspace を使用している場合は、オンボーディング時に google-maps-platform-sdk-users@workspacedomain.com などのワークスペース グループを作成し、Google に名前を指定します。これはおすすめの方法です。 次に、ワークスペース グループが、Maven リポジトリ gmp-artifacts/transportation へのアクセスを許可する許可リストに追加されます。アクセス権を必要とするユーザーのメールアドレスとサービス アカウントのメールアドレスがこのリストに含まれていることを確認します。

組織で Workspace グループを作成できない場合は、これらのアーティファクトにアクセスする必要があるユーザーとサービス アカウントのメールアドレスのリストを Google に送信します。

ローカルでの開発

ローカル開発では、Cloud SDK でログインするだけで十分です。

gcloud

gcloud auth login

ログインに使用するメールアドレスは、Workspace グループのメンバーである必要があります。

自動化(ビルドシステムまたは継続的インテグレーション)

ベスト プラクティスに従って自動化ホストを設定します。

  • プロセスが Google Cloud 環境内で実行されている場合は、自動認証情報検出を使用します。

  • それ以外の場合は、ホストのファイル システムの安全な場所にサービス アカウント キー ファイルを保存し、GOOGLE_APPLICATION_CREDENTIALS 環境変数を適切に設定します。

認証情報に関連付けられたサービス アカウントのメールアドレスは、Workspace グループのメンバーである必要があります。

構成

ユーザーまたはサービスの認証情報を自動的に検出するように Maven または Gradle を構成します。

Gradle

プロジェクト ルート モジュール build.gradle ファイルではなく、アプリ モジュールの build.gradle ファイルに追加します。

  plugins {
    id "com.google.cloud.artifactregistry.gradle-plugin" version "2.1.5"
  }
  repositories {
    maven {
      url "artifactregistry://us-west2-maven.pkg.dev/gmp-artifacts/transportation"
    }
  }

Maven

pom.xml に次の行を追加します。

  <repositories>
    <repository>
      <id>gmp-artifacts</id>
      <url>artifactregistry://us-west2-maven.pkg.dev/gmp-artifacts/transportation</url>
      <releases>
        <enabled>true</enabled>
      </releases>
    </repository>
  </repositories>
  <build>
    <extensions>
      <extension>
        <groupId>com.google.cloud.artifactregistry</groupId>
        <artifactId>artifactregistry-maven-wagon</artifactId>
        <version>2.1.0</version>
      </extension>
    </extensions>
  </build>

アクセスの確認については、Java パッケージの管理をご覧ください。

Project Configuration

Driver SDK を使用するには、アプリで minSdkVersion 21 以降をターゲットにする必要があります。

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

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

開発プロジェクトを設定して、Google Cloud Console でプロジェクトの API キーを取得するには:

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

  2. デモアプリを実行するには、プロジェクトに Maps SDK for Android へのアクセス権が付与されている必要があります。Google Cloud Console で、[API とサービス] > [ライブラリ] を選択し、Maps SDK for Android を検索して有効にします。

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

アプリに Driver SDK を追加する

Driver SDK は非公開の Maven リポジトリから入手できます。リポジトリには、SDK の Project Object Model(.pom)ファイルと Javadocs が含まれています。Driver SDK をアプリに追加するには:

  1. アクセス権の取得の説明に従って、ホスト Maven リポジトリにアクセスするように環境を設定します。
  2. Gradle または Maven 構成に次の依存関係を追加します。VERSION_NUMBER プレースホルダは、目的のドライバ用ドライバの SDK のバージョンに置き換えてください。

    Gradle

    build.gradle に次の行を追加します。

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

    Maven

    pom.xml に次の行を追加します。

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-driver</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    

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

Driver 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.driverapidemo">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_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>

必須の帰属情報をアプリに含める

アプリで Driver SDK を使用する場合は、アプリの法的通知セクションの一部として、アトリビューション テキストとオープンソース ライセンスを含める必要があります。アトリビューションは、独立したメニュー項目として、または [概要] メニュー項目の一部として含めることをおすすめします。

必要なアトリビューション テキストとオープンソース ライセンスは、Driver SDK の zip ファイルで確認できます。

  • NOTICE.txt
  • LICENSES.txt

依存関係

ProGuard を使用してビルドを最適化する場合は、ProGuard 構成ファイルに次の行を追加する必要があります。

-dontwarn com.google.**
-dontwarn okio.**

サポートされる最小 API レベルは 21 です。

SDK の初期化

DriverContext オブジェクトを初期化するには、プロバイダ ID(通常は Google Cloud プロジェクト ID)が必要です。Google Cloud プロジェクトの設定の詳細については、認証と認可をご覧ください。

Driver SDK を使用する前に、Navigation SDK を初期化する必要があります。SDK を初期化するには:

  1. NavigationApi から Navigator オブジェクトを取得します。

    Java

    NavigationApi.getNavigator(
        this, // Activity
        new NavigationApi.NavigatorListener() {
          @Override
          public void onNavigatorReady(Navigator navigator) {
            // Keep a reference to the Navigator (used to configure and start nav)
            this.navigator = navigator;
          }
        }
    );
    

    Kotlin

    NavigationApi.getNavigator(
      this, // Activity
      object : NavigatorListener() {
        override fun onNavigatorReady(navigator: Navigator) {
          // Keep a reference to the Navigator (used to configure and start nav)
          this@myActivity.navigator = navigator
        }
      },
    )
    
  2. DriverContext オブジェクトを作成し、必須項目に入力します。

    Java

    DriverContext driverContext = DriverContext.builder(application)
        .setProviderId(providerId)
        .setVehicleId(vehicleId)
        .setAuthTokenFactory(authTokenFactory)
        .setNavigator(navigator)
        .setRoadSnappedLocationProvider(
            NavigationApi.getRoadSnappedLocationProvider(application))
        .build();
    

    Kotlin

    val driverContext =
      DriverContext.builder(application)
        .setProviderId(providerId)
        .setVehicleId(vehicleId)
        .setAuthTokenFactory(authTokenFactory)
        .setNavigator(navigator)
        .setRoadSnappedLocationProvider(NavigationApi.getRoadSnappedLocationProvider(application))
        .build()
    
  3. DriverContext オブジェクトを使用して *DriverApi を初期化します。

    Java

    RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
    

    Kotlin

    val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
    
  4. API オブジェクトから RidesharingVehicleReporter を取得します。(*VehicleReporterNavigationVehicleReporter を拡張します)。

    Java

    RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
    

    Kotlin

    val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
    

AuthTokenFactory による認証

Driver SDK が位置情報の更新を生成したら、これらの更新を Fleet Engine サーバーに送信する必要があります。これらのリクエストを認証するために、Driver SDK は呼び出し元が提供する AuthTokenFactory のインスタンスを呼び出します。工場では、位置情報の更新時に認証トークンを生成します。

生成されるトークンはデベロッパーごとに異なります。ただし、実装で次のことが必要となる可能性があります。

  • HTTPS サーバーから認証トークン(JSON 形式の可能性あり)を取得します。
  • トークンを解析してキャッシュに保存する
  • 有効期限が切れたらトークンを更新する

Fleet Engine サーバーで想定されるトークンの詳細については、認可用の JSON ウェブトークン(JWT)の作成をご覧ください。

AuthTokenFactory のスケルトン実装を次に示します。

Java

class JsonAuthTokenFactory implements AuthTokenFactory {
  private String token;  // initially null
  private long expiryTimeMs = 0;

  // This method is called on a thread whose only responsibility is to send
  // location updates. Blocking is OK, but just know that no location updates
  // can occur until this method returns.
  @Override
  public String getToken(AuthTokenContext authTokenContext) {
    if (System.currentTimeMillis() > expiryTimeMs) {
      // The token has expired, go get a new one.
      fetchNewToken(authTokenContext.getVehicleId());
    }
    return token;
  }

  private void fetchNewToken(String vehicleId) {
    String url =
        new Uri.Builder()
            .scheme("https")
            .authority("yourauthserver.example")
            .appendPath("token")
            .appendQueryParameter("vehicleId", vehicleId)
            .build()
            .toString();

    try (Reader r = new InputStreamReader(new URL(url).openStream())) {
      com.google.gson.JsonObject obj
          = com.google.gson.JsonParser.parseReader(r).getAsJsonObject();
      token = obj.get("Token").getAsString();
      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 10 minutes from that time.
      expiryTimeMs -= 10 * 60 * 1000;
    } catch (IOException e) {
      // It's OK to throw exceptions here. The StatusListener you passed to
      // create the DriverContext class will be notified and passed along the failed
      // update warning.
      throw new RuntimeException("Could not get auth token", e);
    }
  }
}

Kotlin

class JsonAuthTokenFactory : AuthTokenFactory() {

  private var token: String = ""
  private var expiryTimeMs: Long = 0

  // This method is called on a thread whose only responsibility is to send
  // location updates. Blocking is OK, but just know that no location updates
  // can occur until this method returns.
  override fun getToken(context: AuthTokenContext): String {
    if (System.currentTimeMillis() > expiryTimeMs) {
      // The token has expired, go get a new one.
      fetchNewToken(authTokenContext.getVehicleId())
    }
     return token
  }

  fun fetchNewToken(vehicleId: String) {
    val url =
      Uri.Builder()
        .scheme("https")
        .authority("yourauthserver.example")
        .appendPath("token")
        .appendQueryParameter("vehicleId", vehicleId)
        .build()
        .toString()

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

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

        token = obj.get("ServiceToken").getAsString()
        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 10 minutes from that time.
        expiryTimeMs -= 10 * 60 * 1000
      }
    } catch (e: IOException) {
      // It's OK to throw exceptions here. The StatusListener you passed to
      // create the DriverContext class will be notified and passed along the failed
      // update warning.
      throw RuntimeException("Could not get auth token", e)
    }
  }
}

この実装では、組み込みの Java HTTP クライアントを使用して、デベロッパーの認証サーバーから JSON 形式のトークンを取得します。トークンは再利用のために保存されます。トークンは、有効期限の 10 分以内に古いトークンが再取得されます。

実装によっては、トークンの更新にバックグラウンド スレッドを使用するなど、別の動作をすることもあります。

AuthTokenFactory で例外が繰り返されない限り、例外は一時的なものとして扱われます。ドライバ SDK では何度か試行した後、エラーが永続的であると想定し、更新の送信を停止します。

StatusListener でのステータスと Error Reporting

Driver SDK はバックグラウンドでアクションを実行するため、StatusListener を使用して、エラー、警告、デバッグ メッセージなどの特定のイベントが発生したときに通知をトリガーします。エラーは性質上(BACKEND_CONNECTIVITY_ERROR など)に発生することがあります。また、位置情報の更新が恒久的に停止する(VEHICLE_NOT_FOUND など)ことで構成エラーが発生することがあります。

次のような StatusListener の実装(省略可)を指定します。

Java

class MyStatusListener implements StatusListener {
  /** Called when background status is updated, during actions such as location reporting. */
  @Override
  public void updateStatus(
      StatusLevel statusLevel, StatusCode statusCode, String statusMsg) {
    // Status handling stuff goes here.
    // StatusLevel may be DEBUG, INFO, WARNING, or ERROR.
    // StatusCode may be DEFAULT, UNKNOWN_ERROR, VEHICLE_NOT_FOUND,
    // BACKEND_CONNECTIVITY_ERROR, or PERMISSION_DENIED.
  }
}

Kotlin

class MyStatusListener : StatusListener() {
  /** Called when background status is updated, during actions such as location reporting. */
  override fun updateStatus(statusLevel: StatusLevel, statusCode: StatusCode, statusMsg: String) {
    // Status handling stuff goes here.
    // StatusLevel may be DEBUG, INFO, WARNING, or ERROR.
    // StatusCode may be DEFAULT, UNKNOWN_ERROR, VEHICLE_NOT_FOUND,
    // BACKEND_CONNECTIVITY_ERROR, or PERMISSION_DENIED.
  }
}

SSL/TLS に関する注意事項

内部的には、Driver SDK の実装は SSL/TLS を使用して Fleet Engine サーバーと安全に通信します。古いバージョンの Android(API バージョン 19 以前)では、サーバーと通信するために SecurityProvider パッチが必要になる場合があります。Android での SSL の操作について詳しくは、こちらの記事をご覧ください。この記事では、セキュリティ プロバイダにパッチを適用するためのコードサンプルについても説明します。

位置情報の更新を有効にする

*VehicleReporter インスタンスを取得すると、位置情報の更新の有効化は簡単です。

Java

RidesharingVehicleReporter reporter = ...;

reporter.enableLocationTracking();

Kotlin

val reporter = ...

reporter.enableLocationTracking()

車両の状態が ONLINE になると、位置情報の更新が定期的に送信されます。reporter.enableLocationTracking() を呼び出しても、車両の状態が自動的に ONLINE に設定されることはありません。車両の状態を明示的に設定する必要があります。

デフォルトでは、レポート間隔は 10 秒です。レポート間隔は reporter.setLocationReportingInterval(long, TimeUnit) で変更できます。サポートされている最小更新間隔は 5 秒です。頻繁に更新すると、リクエストやエラーが遅くなる可能性があります。

位置情報の更新を無効にする

ドライバーのシフトが終了したら、DeliveryVehicleReporter.disableLocationTracking または RidesharingVehicleReporter.disableLocationTracking を呼び出すことで、位置情報の更新を停止し、車両をオフラインとしてマークできます。

この呼び出しにより、車両がオフラインであることを示す最後の更新が即座に配信されるようにスケジュールされます。このアップデートには、ユーザーの位置情報は含まれません。

車両の状態の設定

位置情報の更新が有効な場合、車両の状態を ONLINE に設定すると、車両を SearchVehicles クエリで使用できるようになります。同様に、車両に OFFLINE マークを付けると、車両は利用不可になります。

サーバー側で車両の状態を設定する(車両を更新するを参照)、または Driver SDK で直接設定することもできます。

Java

RidesharingVehicleReporter reporter = ...;

reporter.enableLocationTracking();
reporter.setVehicleState(VehicleState.ONLINE);

Kotlin

val reporter = ...

reporter.enableLocationTracking()
reporter.setVehicleState(VehicleState.ONLINE)

位置情報の更新が有効になっている場合、setVehicleState の呼び出しは次の位置情報の更新時に伝播されます。

位置情報の追跡が有効になっていない場合に車両に ONLINE マークを付けると、IllegalStateException になります。位置情報の追跡がまだ有効になっていないか、明示的に無効にされている場合、車両は OFFLINE とマークされます。これにより、直ちに更新されます。RidesharingVehicleReporter.disableLocationTracking() を呼び出すと、車両の状態が OFFLINE に設定されます。

setVehicleState は即座に返され、更新は位置情報の更新スレッドで行われます。位置情報の更新のエラー処理と同様に、車両状態の更新エラーは、オプションで DriverContext に設定された StatusListener を使用して伝播されます。