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:
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.
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.
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:
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>
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:
Otwórz plik
build.gradle
poziomu głównego i dodaj poniższy kod do elementudependencies
wbuildscript
.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") } }
Otwórz plik
build.gradle
na poziomie aplikacji i dodaj poniższy kod do elementuplugins
.Zakręcony
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
Kotlin
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
Jeśli używasz Androida Studio, zsynchronizuj projekt z Gradle.
Otwórz
local.properties
w katalogu na poziomie projektu, a następnie dodaj ten kod. ZastąpYOUR_API_KEY
swoim kluczem interfejsu API.MAPS_API_KEY=YOUR_API_KEY
W pliku
AndroidManifest.xml
przejdź do miejscacom.google.android.geo.API_KEY
i zaktualizuj atrybutandroid: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:
Uzyskaj obiekt
Navigator
zNavigationApi
.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 } }, )
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()
Zainicjuj obiekt
*DriverApi
za pomocą obiektuDriverContext
.Java
RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
Kotlin
val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
Uzyskaj
RidesharingVehicleReporter
z obiektu interfejsu API. (*VehicleReporter
przedłuża się oNavigationVehicleReporter
).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
.