Вы можете использовать Driver SDK, чтобы обеспечить расширенную навигацию и отслеживание вашего приложения «Поездки и ход заказа». Driver SDK предоставляет обновленную информацию о местонахождении транспортных средств и задачах для системы On-demand Rides and Delivery Solution Fleet Engine.
Driver SDK информирует службы Fleet Engine и ваши таможенные службы о местонахождении и состоянии транспортного средства. Например, транспортное средство может находиться ONLINE
или OFFLINE
, а местоположение автомобиля меняется по ходу поездки.
Минимальные системные требования
Мобильное устройство должно работать под управлением Android 6.0 (уровень API 23) или более поздней версии.
Конфигурация сборки и зависимостей
Driver SDK версии 4.99 и более поздних версий доступен в репозитории Google Maven.
Градл
Добавьте в файл build.gradle
следующее:
repositories {
...
google()
}
Мавен
Добавьте в файл pom.xml
следующее:
<project>
...
<repositories>
<repository>
<id>google-maven-repository</id>
<url>https://maven.google.com</url>
</repository>
</repositories>
...
</project>
Конфигурация проекта
Чтобы использовать Driver SDK, ваше приложение должно быть нацелено на minSdkVersion
23 или выше.
Чтобы запустить приложение, созданное с помощью Driver SDK, на устройстве Android должны быть установлены службы Google Play .
Настройте свой проект разработки
Чтобы настроить проект разработки и получить ключ API для проекта в Google Cloud Console:
Создайте новый проект Google Cloud Console или выберите существующий проект для использования с Driver SDK. Подождите несколько минут, пока новый проект не появится в Google Cloud Console.
Чтобы запустить демонстрационное приложение, у вашего проекта должен быть доступ к Maps SDK для Android. В Google Cloud Console выберите API и службы > Библиотека , затем найдите и включите Maps SDK для Android.
Получите ключ API для проекта, выбрав API и службы > Учетные данные > Создать учетные данные > Ключ API . Дополнительную информацию о получении ключа API см. в разделе Получение ключа API .
Добавьте Driver SDK в свое приложение
Driver SDK доступен в репозитории Google Maven. Репозиторий включает файлы объектной модели проекта SDK (.pom) и документацию Javadocs. Чтобы добавить Driver SDK в ваше приложение:
Добавьте следующую зависимость в конфигурацию Gradle или Maven, заменив заполнитель
VERSION_NUMBER
на нужную версию Driver SDK.Градл
Добавьте следующее в свой
build.gradle
:dependencies { ... implementation 'com.google.android.libraries.mapsplatform.transportation:transportation-driver:VERSION_NUMBER' }
Мавен
Добавьте следующее в ваш
pom.xml
:<dependencies> ... <dependency> <groupId>com.google.android.libraries.mapsplatform.transportation</groupId> <artifactId>transportation-driver</artifactId> <version>VERSION_NUMBER</version> </dependency> </dependencies>
Driver SDK зависит от Navigation SDK. Эта зависимость настроена таким образом, что если требуется конкретная версия Navigation SDK, ее необходимо явно определить в файле конфигурации сборки, как показано ниже. Пропуск упомянутого блока кода включит проект чтобы всегда загружать последнюю версию Navigation SDK в рамках основной версии. Обратите внимание, что совместное поведение последних версий Driver SDK и Navigation SDK прошло тщательное тестирование перед их выпуском.
Соответствующим образом организуйте конфигурацию зависимостей вашей среды разработки и выпуска.
Градл
Добавьте следующее в свой
build.gradle
:dependencies { ... implementation 'com.google.android.libraries.navigation:navigation:5.0.0' }
Мавен
Добавьте следующее в ваш
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 .
Чтобы упростить эту задачу, вы можете использовать плагин Secrets Gradle для Android .
Чтобы установить плагин и сохранить ключ API:
Откройте файл
build.gradle
корневого уровня и добавьте следующий код в элементdependencies
вbuildscript
.классный
buildscript { dependencies { // ... classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.0" } }
Котлин
buildscript { dependencies { // ... classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.0") } }
Откройте файл
build.gradle
уровня приложения и добавьте следующий код в элементplugins
.классный
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
Котлин
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
Если вы используете Android Studio, синхронизируйте свой проект с Gradle .
Откройте
local.properties
в каталоге уровня вашего проекта, а затем добавьте следующий код. ЗаменитеYOUR_API_KEY
своим ключом API.MAPS_API_KEY=YOUR_API_KEY
В файле
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 в своем приложении, вы должны включить текст указания авторства и лицензии с открытым исходным кодом в раздел юридических уведомлений вашего приложения. Лучше всего включить атрибуцию как независимый пункт меню или как часть пункта меню «О программе» .
Информацию о лицензиях можно найти в файле Third_party_licenses.txt в разархивированном файле AAR.
Инструкции по включению уведомлений об открытом исходном коде см. на странице https://developers.google.com/android/guides/opensource .
Зависимости
Если вы используете ProGuard для оптимизации своих сборок, вам может потребоваться добавить следующие строки в файл конфигурации ProGuard:
-dontwarn com.google.**
-dontwarn okio.**
Минимальный поддерживаемый уровень API — 23.
Инициализация SDK
Идентификатор поставщика (обычно идентификатор проекта Google Cloud) необходим для инициализации объекта DriverContext
. Более подробную информацию о настройке проекта Google Cloud см. в разделе Аутентификация и авторизация .
Перед использованием Driver SDK необходимо сначала инициализировать Navigation SDK. Чтобы инициализировать SDK:
Получите объект
Navigator
изNavigationApi
.Джава
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; } } );
Котлин
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 } }, )
Создайте объект
DriverContext
, заполнив необходимые поля.Джава
DriverContext driverContext = DriverContext.builder(application) .setProviderId(providerId) .setVehicleId(vehicleId) .setAuthTokenFactory(authTokenFactory) .setNavigator(navigator) .setRoadSnappedLocationProvider( NavigationApi.getRoadSnappedLocationProvider(application)) .build();
Котлин
val driverContext = DriverContext.builder(application) .setProviderId(providerId) .setVehicleId(vehicleId) .setAuthTokenFactory(authTokenFactory) .setNavigator(navigator) .setRoadSnappedLocationProvider(NavigationApi.getRoadSnappedLocationProvider(application)) .build()
Используйте объект
DriverContext
для инициализации*DriverApi
.Джава
RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
Котлин
val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
Получите
RidesharingVehicleReporter
из объекта API. (*VehicleReporter
расширяетNavigationVehicleReporter
.)Джава
RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
Котлин
val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
Аутентификация с помощью AuthTokenFactory
Когда Driver SDK генерирует обновления местоположения, он должен отправлять эти обновления на сервер Fleet Engine. Для аутентификации этих запросов Driver SDK обращается к экземпляру AuthTokenFactory
, предоставленному вызывающей стороной. Фабрика отвечает за создание токенов аутентификации во время обновления местоположения.
То, как именно генерируются токены, будет зависеть от ситуации каждого разработчика. Однако реализация, вероятно, потребует:
- получить токен аутентификации, возможно, в формате JSON, с HTTPS-сервера
- проанализировать и кэшировать токен
- обновить токен по истечении срока его действия
Подробную информацию о токенах, ожидаемых сервером Fleet Engine, см. в разделе Создание веб-токена JSON (JWT) для авторизации .
Вот скелет реализации AuthTokenFactory
:
Джава
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);
}
}
}
Котлин
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)
}
}
}
В этой конкретной реализации используется встроенный HTTP-клиент Java для получения токена в формате JSON с сервера аутентификации разработчика. Токен сохраняется для повторного использования. Токен извлекается повторно, если срок действия старого токена истекает в течение 10 минут.
Ваша реализация может работать по-другому, например использовать фоновый поток для обновления токенов.
Исключения в AuthTokenFactory
будут рассматриваться как временные, если они не происходят повторно. После нескольких попыток Driver SDK посчитает ошибку постоянной и прекратит попытки отправлять обновления.
Отчеты о статусе и ошибках с помощью StatusListener
Поскольку Driver SDK выполняет действия в фоновом режиме, используйте StatusListener
для запуска уведомлений при возникновении определенных событий, таких как ошибки, предупреждения или сообщения отладки. Ошибки могут быть временными по своей природе (например, BACKEND_CONNECTIVITY_ERROR
) или могут привести к постоянной остановке обновления местоположения (например, VEHICLE_NOT_FOUND
, что указывает на ошибку конфигурации).
Вы предоставляете дополнительную реализацию StatusListener
подобную следующей:
Джава
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.
}
}
Котлин
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
для связи с сервером. Вам следует прочитать эту статью для получения дополнительной информации о работе с SSL в Android. Статья также содержит примеры кода для исправления поставщика безопасности.
Включение обновлений местоположения
Если у вас есть экземпляр *VehicleReporter
, включить обновление местоположения очень просто:
Джава
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
Котлин
val reporter = ...
reporter.enableLocationTracking()
Обновления местоположения отправляются через регулярные промежутки времени, когда транспортное средство находится в режиме ONLINE
. Обратите внимание, что вызов reporter.enableLocationTracking()
не устанавливает автоматически состояние транспортного средства в ONLINE
. Вы должны явно указать состояние транспортного средства .
По умолчанию интервал отчетов составляет 10 секунд. Интервал отчетности можно изменить с помощью reporter.setLocationReportingInterval(long, TimeUnit)
. Минимальный поддерживаемый интервал обновления составляет 5 секунд. Более частые обновления могут привести к замедлению запросов и ошибкам.
Отключение обновления местоположения
Когда смена водителя завершена, обновление местоположения можно остановить и пометить транспортное средство как отключенное от сети, вызвав DeliveryVehicleReporter.disableLocationTracking
или RidesharingVehicleReporter.disableLocationTracking
.
Этот вызов приведет к тому, что одно последнее обновление будет запланировано для немедленной доставки, что указывает на то, что автомобиль отключен от сети. Это обновление не будет содержать местоположение пользователя.
Настройка состояния автомобиля
Если обновление местоположения включено, установка состояния автомобиля в ONLINE
сделает автомобиль доступным для запросов SearchVehicles
; Аналогичным образом, пометка транспортного средства как OFFLINE
пометит его как недоступное.
У вас есть возможность установить состояние автомобиля на стороне сервера (см. «Обновление автомобиля ») или непосредственно в Driver SDK:
Джава
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
reporter.setVehicleState(VehicleState.ONLINE);
Котлин
val reporter = ...
reporter.enableLocationTracking()
reporter.setVehicleState(VehicleState.ONLINE)
Если обновление местоположения включено, вызов setVehicleState
будет распространяться при следующем обновлении местоположения.
Пометка транспортного средства как ONLINE
, когда отслеживание местоположения не включено, приведет к возникновению IllegalStateException
. Транспортное средство может быть помечено как OFFLINE
если отслеживание местоположения еще не включено или явно отключено. Это приведет к немедленному обновлению. Вызов RidesharingVehicleReporter.disableLocationTracking()
установит состояние транспортного средства в OFFLINE
.
Обратите внимание, что setVehicleState
возвращает результат немедленно, а обновления выполняются в потоке обновления местоположения. Подобно обработке ошибок обновлений местоположений, ошибки обновления состояния транспортного средства распространяются с помощью дополнительно предоставляемого StatusListener
установленного в DriverContext
.