Вы можете использовать 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
.