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

ライセンス情報は、アーカイブ解除された 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 によるステータスとエラーの報告

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 を呼び出すことで、位置情報の更新を停止し、車両をオフラインとしてマークできます。

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

車両の状態の設定

位置情報の更新が有効になっている場合、車両の状態を 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 を使用して伝播されます。