يمكنك استخدام "حزمة تطوير البرامج (SDK) لبرنامج التشغيل" لتوفير إمكانية تنقّل وتتبُّع محسَّنة ضمن تطبيق Trip and Order Progress. توفّر "حزمة تطوير البرامج (SDK) للسائق" تحديثات بشأن موقع المركبة ومهامها ضمن محرّك حلول عمليات النقل عند الطلب والتسليمات.
تُبقي "حزمة تطوير البرامج (SDK) للسائق" خدمات Fleet Engine وخدماتك المخصَّصة على علم بموقع المركبة وحالتها. على سبيل المثال، يمكن أن تكون المركبة ONLINE
أو OFFLINE
، ويتغير الموقع الجغرافي للمركبة مع تقدّم الرحلة.
الحد الأدنى لمتطلبات النظام
يجب أن يعمل الجهاز الجوّال بالإصدار 6.0 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات) أو بإصدار أحدث.
تكوين الإصدار والتبعيات
يتوفّر الإصدار 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، يجب أن يستهدف تطبيقك الإصدار 23 من
minSdkVersion
أو الإصدارات الأحدث.
لتشغيل تطبيق تم إنشاؤه باستخدام Driver SDK، يجب تثبيت خدمات Google Play على جهاز Android.
إعداد مشروع التطوير
لإعداد مشروع التطوير والحصول على مفتاح واجهة برمجة تطبيقات للمشروع على Google Cloud Console:
أنشئ مشروعًا جديدًا على Google Cloud Console أو اختَر مشروعًا حاليًا لاستخدامه مع Driver SDK. انتظر بضع دقائق حتى يظهر المشروع الجديد على Google Cloud Console.
من أجل تشغيل التطبيق التجريبي، يجب أن تتوفّر لمشروعك إذن الوصول إلى حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" لنظام التشغيل Android. في Google Cloud Console، اختَر واجهات برمجة التطبيقات والخدمات > المكتبة، ثم ابحث عن حزمة تطوير البرامج (SDK) للخرائط وفعّلها لنظام التشغيل Android.
احصل على مفتاح واجهة برمجة تطبيقات للمشروع من خلال اختيار واجهات برمجة التطبيقات والخدمات > بيانات الاعتماد > إنشاء بيانات الاعتماد > مفتاح واجهة برمجة التطبيقات. لمزيد من المعلومات حول الحصول على مفتاح واجهة برمجة التطبيقات، يُرجى الاطّلاع على الحصول على مفتاح واجهة برمجة التطبيقات.
إضافة حزمة تطوير البرامج (SDK) لبرنامج التشغيل إلى تطبيقك
تتوفّر حزمة Driver SDK في مستودع Google Maven. يتضمّن المستودع ملفات نموذج كائن المشروع (pom.) الخاصة بحزمة SDK وJavadocs. لإضافة حزمة تطوير البرامج (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>
تعتمد حزمة تطوير البرامج (SDK) لبرنامج التشغيل على حزمة تطوير البرامج (SDK) للتنقّل، ويتم ضبط هذه التبعية بطريقة تتيح للمشروع إمكانية تنزيل أحدث إصدار دائمًا من حزمة التنقّل في الإصدار الرئيسي، في حال الحاجة إلى إصدار معيّن من حزمة SDK للتنقّل، وذلك بشكل صريح في ملف إعداد الإصدار كالتالي. تجدر الإشارة إلى أنّ السلوكيات المُجمّعة لأحدث إصدارات Driver SDK وحزمة تطوير البرامج (SDK) للتنقّل قد خضعت لاختبارات صارمة قبل إطلاقهما.
رتب تكوين التبعية للتطوير وأطلق البيئات وفقًا لذلك.
Gradle
أضِف ما يلي إلى
build.gradle
:dependencies { ... implementation 'com.google.android.libraries.navigation:navigation:5.0.0' }
Maven
أضِف ما يلي إلى
pom.xml
:<dependencies> ... <dependency> <groupId>com.google.android.libraries.navigation</groupId> <artifactId>navigation</artifactId> <version>5.0.0</version> </dependency> </dependencies>
إضافة مفتاح واجهة برمجة التطبيقات إلى تطبيقك
بعد إضافة حزمة Driver SDK إلى تطبيقك، أضِف مفتاح واجهة برمجة التطبيقات إلى تطبيقك. ويجب استخدام مفتاح واجهة برمجة تطبيقات المشروع الذي حصلت عليه عند إعداد مشروع التطوير.
يوضّح هذا القسم طريقة تخزين مفتاح واجهة برمجة التطبيقات كي يمكن الإشارة إليه بشكل أكثر أمانًا من خلال تطبيقك. ويجب عدم التحقّق من مفتاح واجهة برمجة التطبيقات في نظام التحكّم في الإصدار. ويجب تخزينها في ملف local.properties
الموجود في الدليل الجذري لمشروعك. لمزيد من المعلومات حول ملف local.properties
، راجِع ملفات خصائص Gradle.
لتبسيط هذه المهمة، يمكنك استخدام المكوّن الإضافي Secret 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>
إدراج عمليات تحديد المصدر المطلوبة في تطبيقك
إذا كنت تستخدم "حزمة تطوير البرامج (SDK) لبرنامج التشغيل" في تطبيقك، عليك تضمين نص الإحالة وتراخيص البرامج المفتوحة المصدر كجزء من قسم الإشعارات القانونية في تطبيقك. ومن الأفضل تضمين عمليات الإحالة كعنصر قائمة مستقل أو كجزء من عنصر قائمة لمحة.
يمكن العثور على معلومات التراخيص في ملف "third_party_ Licenses.txt" في ملف AAR غير المؤرشف.
يمكنك الرجوع إلى https://developers.google.com/android/guides/opensource حول كيفية تضمين إشعارات البرامج المفتوحة المصدر.
التبعيات
إذا كنت تستخدم ProGuard لتحسين إصداراتك، فقد تحتاج إلى إضافة الأسطر التالية إلى ملف إعداد ProGuard:
-dontwarn com.google.**
-dontwarn okio.**
الحد الأدنى لمستوى واجهة برمجة التطبيقات المتوافق هو 23.
جارٍ إعداد حزمة SDK
يجب إدخال رقم تعريف موفّر (يكون عادةً رقم تعريف مشروع Google Cloud) لإعداد عنصر DriverContext
. لمزيد من التفاصيل حول إعداد مشروع Google Cloud، يُرجى الاطّلاع على المصادقة والتفويض.
قبل استخدام حزمة تطوير البرامج (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
كاستثناءات مؤقتة ما لم تحدث بشكل متكرر. بعد عدد من المحاولات، ستفترض حزمة Driver 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 داخليًا
طبقة المقابس الآمنة (SSL)/بروتوكول أمان طبقة النقل (TLS) للاتصال الآمن
بخادم Fleet Engine. وقد تتطلّب الإصدارات القديمة من Android (الإصدار 19 أو الإصدارات الأقدم من واجهة برمجة التطبيقات) رمز تصحيح SecurityProvider
لتتمكّن من الاتصال بالخادم. من المفترض أن تظهر لك هذه المقالة لمزيد من المعلومات حول العمل باستخدام طبقة المقابس الآمنة (SSL) في 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
.