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

Driver SDK を使用すると、移動と注文の進行状況アプリに高度なナビゲーションとトラッキングを提供できます。Driver SDK は、オンデマンド配車と配達のソリューション Fleet Engine に車両の位置情報とタスクの更新を提供します。

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

最小システム要件

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

ビルドと依存関係の構成

Driver SDK バージョン 4.99 以降は、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

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

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

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

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

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

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

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

Driver SDK をアプリに追加する

Driver SDK は Google Maven リポジトリから入手できます。リポジトリには、SDK のプロジェクト オブジェクト モデル(.pom)ファイルと Javadocs が含まれています。Driver SDK をアプリに追加するには:

  1. Gradle または Maven の構成に次の依存関係を追加します。VERSION_NUMBER プレースホルダは、目的の Driver 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>
    
  2. Driver SDK は Navigation SDK に依存します。この依存関係は、Navigation SDK の特定のバージョンが必要な場合、以下のようにビルド構成ファイルで明示的に定義する必要があります。上記のコードブロックを省略すると、プロジェクトはメジャー リリース バージョン内の Navigation SDK の最新バージョンを常にダウンロードできます。Driver SDK と Navigation SDK の最新バージョンの動作は、リリース前に厳格なテストを受けています。

    それに応じて、開発環境とリリース環境の依存関係構成を調整します。

    Gradle

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

    dependencies {
      ...
      implementation 'com.google.android.libraries.navigation:navigation:5.0.0'
    }
    

    Maven

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

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

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

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

依存関係

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

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

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

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 Web Token(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 での例外は、繰り返し発生しない限り、一時的なものとして扱われます。何度か試行を行うと、Driver SDK はエラーが永続的なものと見なし、アップデートの送信を停止します。

StatusListener を使用した Status と 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 を使用して伝播されます。