Pierwsze kroki z pakietem SDK Driver na Androida

Możesz użyć pakietu Driver SDK, aby usprawnić nawigację i śledzenie w aplikacji Podróże i Postępy zamówień. Pakiet SDK Driver SDK zapewnia aktualizacje lokalizacji pojazdu i zadań w usłudze Fleet Engine usługi Przejazdy i dostawy na żądanie.

Pakiet Driver SDK informuje usługi Fleet Engine i usługi niestandardowe o lokalizacji i stanie pojazdu. Pojazd może na przykład być ONLINE lub OFFLINE, a jego lokalizacja będzie się zmieniać w miarę postępów podróży.

Minimalne wymagania systemowe

Na urządzeniu mobilnym musi być zainstalowany Android 6.0 (poziom interfejsu API 23) lub nowszy.

Konfiguracja kompilacji i zależności

Pakiet SDK sterowników w wersji 4.99 i nowszych jest dostępny w repozytorium Google Maven.

Gradle

Dodaj do pliku build.gradle te informacje:

repositories {
    ...
    google()
}

Maven

Dodaj do pliku pom.xml te informacje:

<project>
  ...
  <repositories>
    <repository>
      <id>google-maven-repository</id>
      <url>https://maven.google.com</url>
    </repository>
  </repositories>
  ...
</project>

Konfiguracja projektu

Aby korzystać z pakietu Driver SDK, Twoja aplikacja musi być kierowana na system minSdkVersion w wersji 23 lub nowszej.

Aby można było uruchomić aplikację utworzoną za pomocą pakietu Driver SDK, na urządzeniu z Androidem muszą być zainstalowane Usługi Google Play.

Konfigurowanie projektu programistycznego

Aby skonfigurować projekt programistyczny i uzyskać dla niego klucz interfejsu API w konsoli Google Cloud:

  1. Utwórz nowy projekt Google Cloud Console lub wybierz istniejący projekt do użycia z pakietem Driver SDK. Zaczekaj kilka minut, aż nowy projekt pojawi się w konsoli Google Cloud.

  2. Aby uruchomić aplikację demonstracyjną, Twój projekt musi mieć dostęp do pakietu SDK Map Google na Androida. W konsoli Google Cloud wybierz Interfejsy API i usługi > Biblioteka, a następnie wyszukaj i włącz pakiet SDK Map Google na Androida.

  3. Aby uzyskać klucz interfejsu API dla projektu, wybierz Interfejsy API i usługi > Dane logowania > Utwórz dane logowania > Klucz interfejsu API. Więcej informacji o uzyskiwaniu klucza interfejsu API znajdziesz w artykule Uzyskiwanie klucza interfejsu API.

Dodaj do aplikacji pakiet SDK sterownika

Pakiet SDK sterownika jest dostępny w repozytorium Google Maven. Repozytorium zawiera pliki modelu obiektu projektu (.pom) pakietu SDK i dokumenty Javadocs. Aby dodać pakiet SDK sterownika do aplikacji:

  1. Dodaj tę zależność do konfiguracji Gradle lub Maven, zastępując zmienną VERSION_NUMBER odpowiednią wersją pakietu Driver SDK.

    Gradle

    Dodaj do elementu build.gradle:

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

    Maven

    Dodaj do elementu pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-driver</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  2. Pakiet SDK sterownika wymaga pakietu Navigation SDK. Ta zależność jest skonfigurowana w taki sposób, że jeśli potrzebna jest konkretna wersja pakietu Navigation SDK, należy ją wyraźnie zdefiniować w pliku konfiguracji kompilacji jak poniżej. Pominięcie tego bloku kodu umożliwi projektowi pobieranie najnowszej wersji pakietu Navigation SDK z wersji głównej. Pamiętaj, że połączone działania najnowszych wersji pakietów Driver SDK i Nawigacja SDK zostały poddane rygorystycznym testom przed ich premierą.

    Uporządkuj konfigurację zależności w środowisku programistycznym i utwórz odpowiednie środowiska wersji.

    Gradle

    Dodaj do elementu build.gradle:

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

    Maven

    Dodaj do elementu pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.navigation</groupId>
        <artifactId>navigation</artifactId>
        <version>5.0.0</version>
      </dependency>
    </dependencies>
    

Dodawanie klucza interfejsu API do aplikacji

Po dodaniu pakietu SDK sterownika do aplikacji dodaj do niej klucz interfejsu API. Musisz użyć klucza interfejsu API projektu uzyskanego podczas konfigurowania projektu.

Ta sekcja zawiera informacje o tym, jak przechowywać klucz interfejsu API, aby aplikacja mogła bezpieczniej się do niego odwoływać. Nie sprawdzaj klucza interfejsu API w systemie kontroli wersji. Powinna znajdować się w pliku local.properties, który znajduje się w katalogu głównym projektu. Więcej informacji o pliku local.properties znajdziesz w artykule o plikach właściwości Gradle.

Aby uprościć to zadanie, możesz użyć wtyczki Gradle obiektów tajnych na Androida.

Aby zainstalować wtyczkę i zapisać klucz interfejsu API:

  1. Otwórz plik build.gradle najwyższego poziomu i dodaj poniższy kod do elementu dependencies w sekcji buildscript.

    Zakręcony

    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. Otwórz plik build.gradle na poziomie aplikacji i dodaj poniższy kod do elementu plugins.

    Zakręcony

    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
    

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. Jeśli używasz Android Studio, zsynchronizuj swój projekt z Gradle.

  4. Otwórz local.properties w katalogu na poziomie projektu, a potem dodaj ten kod. Zastąp YOUR_API_KEY swoim kluczem interfejsu API.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. W pliku AndroidManifest.xml przejdź do sekcji com.google.android.geo.API_KEY i zaktualizuj atrybut android:value w ten sposób:

    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="${MAPS_API_KEY}" />
    

Ten przykład zawiera pełny plik manifestu przykładowej aplikacji:

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

Uwzględnij w aplikacji wymagane informacje o źródłach

Jeśli w swojej aplikacji używasz pakietu SDK Driver SDK, w sekcji informacji prawnych umieść tekst atrybucji i licencje open source. Informacje o źródłach powinny być dodawane jako niezależne pozycje menu lub jako część menu Informacje.

Informacje o licencjach znajdziesz w pliku „third_party_licenses.txt” w niezarchiwizowanym pliku AAR.

Informacje o tym, jak dodać powiadomienia o otwartym kodzie źródłowym, znajdziesz na stronie https://developers.google.com/android/guides/opensource.

Zależności

Jeśli do optymalizowania kompilacji używasz ProGuard, może być konieczne dodanie do pliku konfiguracji ProGuard tych wierszy:

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

Minimalny obsługiwany poziom interfejsu API to 23.

Inicjowanie pakietu SDK

Do zainicjowania obiektu DriverContext wymagany jest identyfikator dostawcy (zwykle identyfikator projektu Google Cloud). Więcej informacji o konfigurowaniu projektu Google Cloud znajdziesz w artykule na temat uwierzytelniania i autoryzacji.

Przed skorzystaniem z pakietu Driver SDK musisz go najpierw zainicjować. Aby zainicjować pakiet SDK:

  1. Uzyskaj obiekt Navigator z klasy NavigationApi.

    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. Utwórz obiekt DriverContext, wypełniając wymagane pola.

    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. Użyj obiektu DriverContext do zainicjowania *DriverApi.

    Java

    RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
    

    Kotlin

    val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
    
  4. Uzyskaj RidesharingVehicleReporter z obiektu interfejsu API. (*VehicleReporter rozszerza NavigationVehicleReporter).

    Java

    RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
    

    Kotlin

    val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
    

Uwierzytelniam w: AuthTokenFactory

Gdy pakiet SDK sterownika generuje aktualizacje lokalizacji, musi je wysyłać do serwera Fleet Engine. Aby uwierzytelnić te żądania, pakiet SDK sterownika będzie wywoływał instancję AuthTokenFactory. Fabryka jest odpowiedzialna za generowanie tokenów uwierzytelniania w czasie aktualizacji lokalizacji.

Sposób generowania tokenów będzie zależeć od sytuacji danego dewelopera. Implementacja prawdopodobnie będzie jednak musiała:

  • Pobranie tokena uwierzytelniania, prawdopodobnie w formacie JSON, z serwera HTTPS
  • analizowanie i buforowanie tokena
  • odśwież token, gdy straci ważność

Informacje o tokenach oczekiwanych przez serwer Fleet Engine znajdziesz w artykule o tworzeniu tokena internetowego JSON (JWT) na potrzeby autoryzacji.

Oto szkielet implementacji obiektu 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)
    }
  }
}

W tej konkretnej implementacji do pobierania tokena w formacie JSON z serwera uwierzytelniania programisty używa wbudowanego klienta HTTP Java. Token zostaje zapisany do ponownego wykorzystania. Token zostanie pobrany ponownie, jeśli stary token wygaśnie w ciągu 10 minut.

Twoja implementacja może działać inaczej, np. odświeżać tokeny przez wątek w tle.

Wyjątki w polu AuthTokenFactory będą traktowane jako przejściowe, chyba że będą się powtarzać. Po kilku próbach pakiet SDK sterownika założy, że błąd jest trwały, i przestanie próbować wysyłać aktualizacje.

Raportowanie stanu i błędów w usłudze StatusListener

Pakiet SDK sterownika wykonuje działania w tle, dlatego używaj polecenia StatusListener do aktywowania powiadomień po wystąpieniu określonych zdarzeń, takich jak błędy, ostrzeżenia czy komunikaty debugowania. Błędy mogą mieć charakter przejściowy (np. BACKEND_CONNECTIVITY_ERROR) lub powodować trwałe zatrzymanie aktualizacji lokalizacji (np. VEHICLE_NOT_FOUND, co wskazuje na błąd konfiguracji).

Podajesz opcjonalną implementację StatusListener, taką jak poniżej:

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.
  }
}

Uwagi dotyczące SSL/TLS

Wewnętrznie implementacja pakietu SDK sterownika używa SSL/TLS do bezpiecznej komunikacji z serwerem Fleet Engine. Starsze wersje Androida (interfejsy API w wersji 19 lub starszej) mogą wymagać poprawki SecurityProvider, aby komunikować się z serwerem. Więcej informacji o pracy z protokołem SSL na Androidzie znajdziesz w tym artykule. Znajdziesz w nim też przykładowy kod do zastosowania poprawek u dostawcy zabezpieczeń.

Włączam aktualizacje lokalizacji

Jeśli masz już instancję *VehicleReporter, włączenie aktualizacji lokalizacji jest proste:

Java

RidesharingVehicleReporter reporter = ...;

reporter.enableLocationTracking();

Kotlin

val reporter = ...

reporter.enableLocationTracking()

Aktualizacje lokalizacji są wysyłane w regularnych odstępach czasu, gdy stan pojazdu to ONLINE. Pamiętaj, że wywołanie numeru reporter.enableLocationTracking() nie powoduje automatycznego ustawienia stanu pojazdu na ONLINE. Musisz wyraźnie ustawić stan pojazdu.

Domyślnie interwał raportowania wynosi 10 sekund. Interwał raportowania można zmienić za pomocą funkcji reporter.setLocationReportingInterval(long, TimeUnit). Minimalny obsługiwany interwał aktualizacji to 5 sekund. Częstsze aktualizacje mogą powodować wolniejsze przesyłanie żądań i błędy.

Wyłączanie aktualizacji lokalizacji

Po zakończeniu zmiany kierowcy można zatrzymać aktualizacje lokalizacji, a pojazd oznaczony jako offline, dzwoniąc do: DeliveryVehicleReporter.disableLocationTracking lub RidesharingVehicleReporter.disableLocationTracking.

To wywołanie spowoduje zaplanowanie natychmiastowej dostawy ostatniej ostatniej aktualizacji, co wskazuje, że pojazd jest offline. Ta aktualizacja nie będzie zawierać lokalizacji użytkownika.

Ustawianie stanu pojazdu

Gdy włączone są aktualizacje lokalizacji, ustawienie stanu pojazdu na ONLINE spowoduje, że pojazd będzie dostępny w przypadku zapytań dotyczących usługi SearchVehicles. Podobnie oznaczenie pojazdu jako OFFLINE spowoduje oznaczenie go jako niedostępnego.

Możesz ustawić stan pojazdu po stronie serwera (patrz Aktualizowanie pojazdu) lub bezpośrednio w pakiecie SDK kierowcy:

Java

RidesharingVehicleReporter reporter = ...;

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

Kotlin

val reporter = ...

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

Gdy aktualizacje lokalizacji są włączone, wywołanie setVehicleState zostanie rozpowszechnione przy następnej aktualizacji lokalizacji.

Jeśli oznaczysz pojazd jako ONLINE, gdy śledzenie lokalizacji nie jest włączone, wyświetli się IllegalStateException. Pojazd może być oznaczony jako OFFLINE, jeśli śledzenie lokalizacji nie jest jeszcze włączone lub wyłączone. W ten sposób powiadomimy Cię o tym natychmiast. Wywołanie RidesharingVehicleReporter.disableLocationTracking() ustawi stan pojazdu na OFFLINE.

Pamiętaj, że setVehicleState zwraca natychmiast, a aktualizacje są wprowadzane w wątku aktualizacji lokalizacji. Podobnie jak w przypadku błędów w przypadku aktualizacji lokalizacji, błędy związane z aktualizacją stanu pojazdu są rozpowszechniane za pomocą opcjonalnie podanego w polu DriverContext parametru StatusListener.