يمكنك استخدام Driver SDK لتوفير تنقل وتتبّع محسّنين لتطبيق تقدّمك في الرحلات والطلبات. توفر Driver SDK تحديثات لموقع المركبات وتحديثات المهام لحلول Fleet Engine المتعلقة بالرحلات والتسليمات عند الطلب.
تعمل حزم SDK للسائق على إطلاع خدمات Fleet Engine والخدمات المخصّصة على موقع المركبة وحالتها. على سبيل المثال، قد تكون المركبة ONLINE
أو OFFLINE
، ويتغير الموقع الجغرافي للمركبة مع تقدّم الرحلة.
الحد الأدنى من متطلبات النظام
يجب أن يعمل الجهاز الجوّال بالإصدار Android 5.0 (المستوى 21 لواجهة برمجة التطبيقات) أو إصدار أحدث.
إعداد Maven
تتوفّر الإصدار 4.99 والإصدارات الأحدث من حزمة تطوير البرامج (SDK) لبرنامج التشغيل في مستودع Google Maven.
Gradle
أضِف ما يلي إلى ملف build.gradle
:
repositories {
...
google()
}
Maven
أضِف ما يلي إلى ملف pom.xml
:
<project>
...
<repositories>
<repository>
<id>google-maven-repository</id>
<url>https://maven.google.com</url>
</repository>
</repositories>
...
</project>
إعدادات المشروع
لاستخدام Driver SDK، يجب أن يستهدف تطبيقك الإصدار 21 من minSdkVersion
أو إصدارات أحدث.
لتشغيل تطبيق تم إنشاؤه باستخدام Driver SDK، يجب تثبيت خدمات Google Play على جهاز Android.
إعداد مشروع التطوير
لإعداد مشروع التطوير الخاص بك والحصول على مفتاح واجهة برمجة تطبيقات للمشروع في Google Cloud Console:
أنشئ مشروعًا جديدًا في Google Cloud Console أو اختَر مشروعًا حاليًا لاستخدامه مع حزمة تطوير البرامج Driver SDK. انتظر بضع دقائق حتى يظهر المشروع الجديد على Google Cloud Console.
من أجل تشغيل التطبيق التجريبي، ينبغي لمشروعك الوصول إلى SDK للخرائط لنظام Android. في Google Cloud Console، اختر واجهات برمجة التطبيقات والخدمات > المكتبة، ثم ابحث عن حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" وفعّلها لنظام التشغيل Android.
يمكنك الحصول على مفتاح واجهة برمجة تطبيقات للمشروع عن طريق اختيار واجهات برمجة التطبيقات والخدمات > بيانات الاعتماد > إنشاء بيانات اعتماد > مفتاح واجهة برمجة التطبيقات. لمزيد من المعلومات حول الحصول على مفتاح واجهة برمجة التطبيقات، يرجى الاطّلاع على الحصول على مفتاح واجهة برمجة التطبيقات.
إضافة Driver SDK إلى تطبيقك
تتوفّر حزمة تطوير البرامج (SDK) لبرنامج التشغيل من خلال مستودع خاص من Maven. يشتمل المستودع على ملفات Project Object Model (.pom) لحزمة SDK وJavaScript. لإضافة Driver SDK إلى تطبيقك:
أضِف التبعية التالية إلى إعدادات Gradle أو Maven، من خلال استبدال العنصر النائب
VERSION_NUMBER
بالإصدار المطلوب من حزمة تطوير البرامج Driver SDK.Gradle
أضِف ما يلي إلى
build.gradle
:dependencies { ... implementation 'com.google.android.libraries.mapsplatform.transportation:transportation-driver:VERSION_NUMBER' }
Maven
أضِف ما يلي إلى
pom.xml
:<dependencies> ... <dependency> <groupId>com.google.android.libraries.mapsplatform.transportation</groupId> <artifactId>transportation-driver</artifactId> <version>VERSION_NUMBER</version> </dependency> </dependencies>
إضافة مفتاح واجهة برمجة التطبيقات إلى تطبيقك
بعد إضافة Driver SDK إلى تطبيقك، أضِف مفتاح واجهة برمجة التطبيقات إلى تطبيقك. عليك استخدام مفتاح واجهة برمجة التطبيقات للمشروع الذي حصلت عليه عند إعداد مشروع التطوير.
يوضّح هذا القسم كيفية تخزين مفتاح واجهة برمجة التطبيقات حتى يتمكن تطبيقك من الرجوع إليه بشكل أكثر أمانًا. ويجب عدم التحقق منه في نظام التحكُّم في الإصدارات. يجب تخزينها في ملف local.properties
، الموجود
في الدليل الجذري لمشروعك. لمزيد من المعلومات حول
ملف local.properties
، راجِع
ملفات خصائص Gradle.
لتسهيل هذه المهمة، يمكنك استخدام المكوّن الإضافي Secrets Gradle الإضافي لأجهزة Android.
لتثبيت المكوّن الإضافي وتخزين مفتاح واجهة برمجة التطبيقات:
افتح ملف
build.gradle
على مستوى الجذر وأضِف الرمز التالي إلى العنصرdependencies
ضمنbuildscript
.رائع
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") } }
افتح ملف
build.gradle
على مستوى التطبيق وأضِف الرمز التالي إلى العنصرplugins
.رائع
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
Kotlin
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
إذا كنت تستخدم "استوديو Android"، عليك مزامنة مشروعك مع Gradle.
افتح
local.properties
في الدليل على مستوى مشروعك، ثم أضِف الرمز التالي. استبدِلYOUR_API_KEY
بمفتاح واجهة برمجة التطبيقات.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 في تطبيقك، عليك تضمين نص الإحالة وتراخيص البرامج المفتوحة المصدر كجزء من قسم الإشعارات القانونية في تطبيقك. من الأفضل تضمين معلومات المساهمين كعنصر مستقل في القائمة أو كجزء من عنصر القائمة حول.
يمكنك العثور على نص الإحالة المطلوب وتراخيص البرامج المفتوحة المصدر في ملف ZIP الخاص بحزمة تطوير البرامج (SDK) لبرنامج التشغيل:
NOTICE.txt
LICENSES.txt
التبعيات
إذا كنت تستخدم ProGuard لتحسين إصداراتك، قد تحتاج إلى إضافة السطور التالية إلى ملف إعداد ProGuard:
-dontwarn com.google.**
-dontwarn okio.**
الحد الأدنى لمستوى واجهة برمجة التطبيقات المعتمد هو 21.
جارٍ إعداد حزمة تطوير البرامج (SDK)
يجب إدخال رقم تعريف موفّر (عادةً رقم تعريف مشروع Google Cloud) لإعداد الكائن DriverContext
. لمزيد من التفاصيل حول إعداد
مشروع Google Cloud، يُرجى الاطّلاع على
المصادقة والتفويض.
قبل استخدام Driver SDK، يجب أولاً تهيئة حزمة SDK للتنقل. لإعداد حزمة تطوير البرامج (SDK):
يمكنك الحصول على عنصر
Navigator
من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 } }, )
أنشئ كائن
DriverContext
، واملأ الحقول المطلوبة.لغة 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()
استخدِم الكائن
DriverContext
لتهيئة*DriverApi
.لغة Java
RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
Kotlin
val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
يمكنك الحصول على
RidesharingVehicleReporter
من كائن واجهة برمجة التطبيقات. (*VehicleReporter
يمتد إلىNavigationVehicleReporter
.)لغة Java
RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
Kotlin
val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
جارٍ المصادقة مع AuthTokenFactory
عندما تنشئ Driver SDK تحديثات للموقع، يجب أن ترسل هذه التحديثات إلى خادم Fleet Engine. لمصادقة هذه الطلبات، ستتصل "حزمة تطوير البرامج (SDK) للسائق" بمثيل AuthTokenFactory
يقدّمه المتصل.
فإن المصنع مسؤول عن إنشاء رموز المصادقة في وقت تحديث الموقع.
ستكون طريقة إنشاء الرموز المميّزة محددة بالنسبة إلى موقف كل مطوّر برامج. ومع ذلك، قد تحتاج عملية التنفيذ إلى ما يلي:
- تجلب رمز مصادقة مميزًا، ربما بتنسيق JSON، من خادم HTTPS
- تحليل الرمز المميّز وتخزينه مؤقتًا
- إعادة تحميل الرمز المميّز عند انتهاء صلاحيته
لمعرفة تفاصيل الرموز المميّزة التي يتوقعها خادم Fleet Engine، يُرجى الاطّلاع على إنشاء رمز JSON المميّز للويب (JWT) للتفويض.
في ما يلي طريقة تنفيذ هيكل 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)
}
}
}
تستخدم عملية التنفيذ هذه تحديدًا عميل Java HTTP المدمَج لجلب رمز مميز بتنسيق JSON من خادم المصادقة الخاص بالمطوّر. يتم حفظ الرمز لإعادة استخدامه. وتتم إعادة جلب الرمز المميّز إذا كان خلال 10 دقائق من تاريخ انتهاء صلاحيته.
قد تنفّذ عملية التنفيذ بعض الإجراءات بشكل مختلف، مثل استخدام سلسلة محادثات في الخلفية لإعادة تحميل الرموز المميّزة.
سيتم التعامل مع الاستثناءات في AuthTokenFactory
على أنّها مؤقتة ما لم تحدث
بشكل متكرّر. وبعد عدة محاولات، ستفترض حزمة تطوير البرامج (SDK) لبرنامج التشغيل أنّ الخطأ دائم وستتوقف عن محاولة إرسال التحديثات.
الإبلاغ عن الحالة والخطأ باستخدام StatusListener
بما أنّ حزمة تطوير البرامج (SDK) الخاصة بالسائق تنفِّذ إجراءات في الخلفية، يمكنك استخدام StatusListener
لإرسال الإشعارات عند وقوع أحداث معيّنة، مثل الأخطاء أو التحذيرات أو رسائل تصحيح الأخطاء. قد تكون الأخطاء عابرة بطبيعتها (مثل BACKEND_CONNECTIVITY_ERROR
)، أو قد تؤدي إلى إيقاف تعديلات الموقع الجغرافي نهائيًا (مثل VEHICLE_NOT_FOUND
، ما يدل على حدوث خطأ في الإعدادات).
تُقدِّم طريقة تنفيذ 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.
}
}
ملاحظات حول طبقة المقابس الآمنة/بروتوكول أمان طبقة النقل (TLS)
داخليًا، يستخدم تطبيق Driver SDK
طبقة المقابس الآمنة/بروتوكول أمان طبقة النقل (TLS) للاتصال بأمان
بخادم Fleet Engine. قد تتطلّب الإصدارات القديمة من Android (الإصدار 19 من واجهة برمجة التطبيقات أو الإصدارات الأقدم) رمز تصحيح SecurityProvider
ليتمكّن من الاتصال
بالخادم. من المفترض أن تطّلِع على هذه
المقالة للحصول على مزيد من المعلومات حول استخدام طبقة المقابس الآمنة في Android. تحتوي المقالة أيضًا
على نماذج تعليمات برمجية لتصحيح موفّر خدمة الأمان.
جارٍ تفعيل تحديثات الموقع الجغرافي
بعد حصولك على مثيل *VehicleReporter
، يتم تفعيل ميزة "تحديثات الموقع الجغرافي"
مباشرةً:
لغة Java
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
Kotlin
val reporter = ...
reporter.enableLocationTracking()
يتم إرسال تعديلات الموقع الجغرافي على فترات منتظمة عندما تكون حالة المركبة هي
ONLINE
. يُرجى العِلم أنّ استدعاء reporter.enableLocationTracking()
لا
يضبط حالة المركبة تلقائيًا على ONLINE
. وعليك
ضبط حالة المركبة بشكل صريح.
بشكل تلقائي، تبلغ مدة إعداد التقارير 10 ثوانٍ. يمكن تغيير الفاصل الزمني لإعداد التقارير باستخدام reporter.setLocationReportingInterval(long, TimeUnit)
. يبلغ الحد الأدنى
للفاصل الزمني للتحديث المتوافق 5 ثوانٍ. وقد تؤدي التحديثات الأكثر تكرارًا
إلى إبطاء الطلبات والأخطاء.
جارٍ إيقاف تحديثات الموقع الجغرافي
عند انتهاء دور السائق، يمكن إيقاف تعديلات الموقع الجغرافي
ووضع علامة "غير متصلة بالإنترنت" على المركبة من خلال الاتصال بالرقم
DeliveryVehicleReporter.disableLocationTracking
أو
RidesharingVehicleReporter.disableLocationTracking
.
ستؤدي هذه المكالمة إلى تحديد موعد تحديث أخير للتسليم الفوري، ما يشير إلى أنّ المركبة غير متصلة بالإنترنت. لن يحتوي هذا التحديث على موقع المستخدم.
جارٍ ضبط حالة المركبة
عند تفعيل ميزة تعديل الموقع الجغرافي، سيؤدي ضبط حالة المركبة على ONLINE
إلى إتاحة المركبة لإجراء طلبات البحث عن SearchVehicles
، وبالمثل، سيؤدي وضع علامة OFFLINE
على مركبة إلى أنّها غير متوفرة.
يمكنك ضبط حالة المركبة على الخادم (راجِع تحديث مركبة)، أو مباشرةً في "حزمة تطوير البرامج (SDK) للسائق":
لغة Java
RidesharingVehicleReporter reporter = ...;
reporter.enableLocationTracking();
reporter.setVehicleState(VehicleState.ONLINE);
Kotlin
val reporter = ...
reporter.enableLocationTracking()
reporter.setVehicleState(VehicleState.ONLINE)
عند تفعيل تحديثات الموقع الجغرافي، سيتم نشر مكالمة إلى setVehicleState
عند
تحديث الموقع الجغرافي التالي.
سيؤدي وضع علامة ONLINE
على مركبة عندما تكون ميزة "تتبُّع الموقع الجغرافي" غير مفعّلة إلى
IllegalStateException
. ويمكن وضع علامة OFFLINE
على مركبة إذا
لم يتم تفعيل ميزة "تتبُّع الموقع الجغرافي" أو إيقافها بشكلٍ صريح. سيؤدي ذلك إلى
تحديث فوري. سيؤدي الاتصال برقم
RidesharingVehicleReporter.disableLocationTracking()
إلى
ضبط حالة المركبة على OFFLINE
.
يُرجى العِلم أنّ setVehicleState
سيعود على الفور ويتم تطبيق التعديلات في سلسلة محادثات تحديث الموقع الجغرافي. كما هي الحال في معالجة الأخطاء المتعلقة بتعديلات المواقع الجغرافية، يتم نشر الأخطاء المتعلقة
بتعديل حالة المركبة باستخدام السمة
StatusListener
المقدَّمة اختياريًا والتي تم ضبطها في DriverContext
.