Pierwsze kroki z pakietem SDK Driver na Androida

Możesz użyć pakietu Driver SDK, aby ulepszyć nawigację i śledzenie w aplikacji Podróż i postęp realizacji zamówienia. Pakiet Driver SDK udostępnia aktualizacje lokalizacji pojazdu i zadań we flocie rozwiązań na żądanie w przejazdach i dostawach.

Pakiet Driver SDK informuje usługi Fleet Engine i usługi niestandardowe o lokalizacji i stanie pojazdu. Na przykład pojazd może być ONLINE lub OFFLINE, a jego lokalizacja zmienia się 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 lub nowszej 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 można było używać pakietu Driver SDK, aplikacja musi być kierowana na system minSdkVersion w wersji 23 lub nowszej.

Aby uruchomić aplikację stworzoną przy użyciu 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 konsoli Google Cloud 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ę w wersji demonstracyjnej, Twój projekt musi mieć dostęp do pakietu Maps SDK na Androida. W konsoli Google Cloud wybierz Interfejsy API i usługi > Biblioteka, a następnie wyszukaj i włącz Maps SDK na Androida.

  3. Aby uzyskać klucz interfejsu API dla projektu, kliknij Interfejsy API i usługi > Dane logowania > Utwórz dane logowania > Klucz interfejsu API. Jeśli chcesz dowiedzieć się, jak uzyskać klucz interfejsu API, przeczytaj, jak uzyskać klucz interfejsu API.

Dodaj pakiet Driver SDK do aplikacji

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

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

    Gradle

    Dodaj do build.gradle:

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

    Maven

    Dodaj do pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-driver</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  2. Pakiet Driver SDK opiera się na pakiecie Navigation SDK. Zależność ta jest skonfigurowana w taki sposób, że jeśli potrzebna jest konkretna wersja pakietu Navigation SDK, trzeba ją wyraźnie zdefiniować w pliku konfiguracji kompilacji, tak jak w przykładzie poniżej. Pominięcie wspomnianego bloku kodu umożliwi projektowi zawsze pobieranie najnowszej wersji pakietu Navigation SDK w ramach wersji głównej. Pamiętaj, że połączone działania najnowszych wersji pakietów Driver SDK i Navigation SDK zostały poddane rygorystycznym testom przed ich opublikowaniem.

    Uporządkuj konfigurację zależności w programie i odpowiednio opublikuj środowiska.

    Gradle

    Dodaj do build.gradle:

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

    Maven

    Dodaj do 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 do aplikacji pakietu Driver SDK dodaj do niej klucz interfejsu API. Musisz użyć klucza interfejsu API projektu uzyskanego podczas konfigurowania projektu programistycznego.

W tej sekcji dowiesz się, jak przechowywać klucz interfejsu API, aby aplikacja mogła lepiej się do niego odwoływać. Nie należy sprawdzać klucza interfejsu API w systemie kontroli wersji. Powinien on być przechowywany 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 usprawnić to zadanie, możesz użyć wtyczki do Gradle obiektów tajnych dla Androida.

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

  1. Otwórz plik build.gradle poziomu głównego i dodaj poniższy kod do elementu dependencies w 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 Androida Studio, zsynchronizuj projekt z Gradle.

  4. Otwórz local.properties w katalogu na poziomie projektu, a następnie 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 miejsca 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>

Umieść w aplikacji wymagane informacje o źródłach

Jeśli w swojej aplikacji używasz pakietu Driver SDK, w sekcji Informacje prawne musisz uwzględnić tekst atrybucji i licencje open source. Informacje o źródłach najlepiej dodawać jako niezależną pozycję menu lub jako część pozycji Informacje.

Informacje o licencjach znajdziesz w pliku „third_party_licenses.txt” w przywróconym pliku AAR.

Informacje o tym, jak dołączać powiadomienia o oprogramowaniu open source, znajdziesz na https://developers.google.com/android/guides/opensource.

Zależności

Jeśli do optymalizacji kompilacji używasz ProGuard, być może trzeba będzie dodać te wiersze do pliku konfiguracji ProGuard:

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

Minimalny obsługiwany poziom interfejsu API to 23.

Inicjowanie pakietu SDK

Identyfikator dostawcy (zwykle identyfikator projektu Google Cloud) jest wymagany do inicjowania obiektu DriverContext. Więcej informacji o konfigurowaniu projektu Google Cloud znajdziesz w artykule Uwierzytelnianie i autoryzacja.

Zanim zaczniesz używać pakietu Driver SDK, musisz najpierw zainicjować pakiet SDK Navigation. Aby zainicjować pakiet SDK:

  1. Uzyskaj obiekt Navigator z 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. Zainicjuj obiekt *DriverApi za pomocą obiektu DriverContext.

    Java

    RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
    

    Kotlin

    val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
    
  4. Uzyskaj RidesharingVehicleReporter z obiektu interfejsu API. (*VehicleReporter przedłuża się o NavigationVehicleReporter).

    Java

    RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
    

    Kotlin

    val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
    

Uwierzytelnianie w sieci AuthTokenFactory

Gdy pakiet Driver SDK generuje aktualizacje lokalizacji, musi je wysłać do serwera Fleet Engine. Aby uwierzytelnić te żądania, pakiet Driver SDK wywołuje podane przez wywołanie metody AuthTokenFactory. Fabryka odpowiada za generowanie tokenów uwierzytelniania w momencie aktualizacji lokalizacji.

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

  • pobranie tokena uwierzytelniania, prawdopodobnie w formacie JSON, z serwera HTTPS
  • przeanalizować token i przechowywać go w pamięci podręcznej
  • odświeżaj token po jego wygaśnięciu

Szczegółowe informacje o tokenach oczekiwanych przez serwer Fleet Engine znajdziesz w artykule Tworzenie tokena internetowego JSON (JWT) na potrzeby autoryzacji.

Oto szkieletowa implementacja elementu 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)
    }
  }
}

Ta konkretna implementacja korzysta z wbudowanego klienta HTTP Java, by pobrać token w formacie JSON z serwera uwierzytelniania dewelopera. Token zaoszczędzisz do ponownego wykorzystania. Jeśli stary token zostanie pobrany w ciągu 10 minut od wygaśnięcia, token zostanie pobrany ponownie.

Implementacja może działać inaczej, np. odświeżać tokeny z użyciem wątku działającego w tle.

Wyjątki w polu AuthTokenFactory będą traktowane jako tymczasowe, chyba że będą się powtarzać. Po kilku próbach pakiet Driver SDK uzna, że błąd jest nieodwracalny i przestanie próbować wysyłać aktualizacje.

Raportowanie stanu i błędów za pomocą usługi StatusListener

Ponieważ pakiet Driver SDK wykonuje działania w tle, używaj zasady StatusListener do aktywowania powiadomień, gdy wystąpią określone zdarzenia, takie jak błędy, ostrzeżenia lub komunikaty debugowania. Błędy mogą być przejściowe (np. BACKEND_CONNECTIVITY_ERROR) lub mogą spowodować trwałe zatrzymanie aktualizacji lokalizacji (np. VEHICLE_NOT_FOUND, co oznacza błąd konfiguracji).

Udostępniasz opcjonalną implementację 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.
  }
}

Uwagi na temat protokołu SSL/TLS

Wewnętrznie implementacja pakietu Driver SDK używa SSL/TLS do bezpiecznej komunikacji z serwerem Fleet Engine. Starsze wersje Androida (interfejs API w wersji 19 lub starszej) mogą wymagać poprawki SecurityProvider do komunikacji z serwerem. Więcej informacji o pracy z protokołem SSL na Androidzie znajdziesz w tym artykule. Artykuł zawiera też przykładowy kod służący do instalowania poprawek dostawcy zabezpieczeń.

Włączam aktualizacje lokalizacji

Gdy masz 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 metody reporter.enableLocationTracking() nie powoduje automatycznego ustawienia stanu pojazdu na ONLINE. Musisz bezpośrednio ustawić stan pojazdu.

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

Wyłączanie aktualizacji lokalizacji

Po zakończeniu zmiany lokalizacji kierowcy można zatrzymać aktualizowanie lokalizacji, a pojazd oznaczyć jako offline, wywołując opcję DeliveryVehicleReporter.disableLocationTracking lub RidesharingVehicleReporter.disableLocationTracking.

Spowoduje to zaplanowanie natychmiastowej aktualizacji ostatniej aktualizacji, co będzie oznaczało, że pojazd jest offline. Ta aktualizacja nie będzie zawierać lokalizacji użytkownika.

Ustawianie stanu pojazdu

Gdy aktualizacje lokalizacji są włączone, ustawienie stanu pojazdu na ONLINE spowoduje, że będzie on dostępny w przypadku zapytań SearchVehicles. Analogicznie oznaczenie pojazdu jako OFFLINE spowoduje, że zostanie on oznaczony jako niedostępny.

Stan pojazdu możesz ustawić po stronie serwera (patrz Aktualizowanie pojazdu) lub bezpośrednio w pakiecie SDK sterownika:

Java

RidesharingVehicleReporter reporter = ...;

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

Kotlin

val reporter = ...

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

Jeśli aktualizacje lokalizacji są włączone, wywołanie setVehicleState zostanie wykonane przy następnej aktualizacji lokalizacji.

Oznaczenie pojazdu jako ONLINE przy wyłączonym śledzeniu lokalizacji spowoduje wyświetlenie prośby o IllegalStateException. Pojazd może zostać oznaczony jako OFFLINE, jeśli śledzenie lokalizacji nie jest jeszcze włączone lub wyłączone. Spowoduje to natychmiastową aktualizację. Wywołanie RidesharingVehicleReporter.disableLocationTracking() spowoduje ustawienie stanu pojazdu na OFFLINE.

Pamiętaj, że funkcja setVehicleState wraca natychmiast, a aktualizacje są przeprowadzane w wątku aktualizacji lokalizacji. Podobnie jak w przypadku obsługi błędów w aktualizacji lokalizacji, błędy aktualizacji stanu pojazdu są rozpowszechniane za pomocą opcjonalnie podanego parametru StatusListener w DriverContext.