يتوفّر حلّ الرحلات وعمليات التسليم عند الطلب حاليًا لشركاء محدّدين فقط.

بدء استخدام SDK Driver لنظام التشغيل Android

يمكنك استخدام 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:

  1. أنشئ مشروعًا جديدًا في Google Cloud Console أو اختَر مشروعًا حاليًا لاستخدامه مع حزمة تطوير البرامج Driver SDK. انتظر بضع دقائق حتى يظهر المشروع الجديد على Google Cloud Console.

  2. من أجل تشغيل التطبيق التجريبي، ينبغي لمشروعك الوصول إلى SDK للخرائط لنظام Android. في Google Cloud Console، اختر واجهات برمجة التطبيقات والخدمات > المكتبة، ثم ابحث عن حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" وفعّلها لنظام التشغيل Android.

  3. يمكنك الحصول على مفتاح واجهة برمجة تطبيقات للمشروع عن طريق اختيار واجهات برمجة التطبيقات والخدمات > بيانات الاعتماد > إنشاء بيانات اعتماد > مفتاح واجهة برمجة التطبيقات. لمزيد من المعلومات حول الحصول على مفتاح واجهة برمجة التطبيقات، يرجى الاطّلاع على الحصول على مفتاح واجهة برمجة التطبيقات.

إضافة Driver SDK إلى تطبيقك

تتوفّر حزمة تطوير البرامج (SDK) لبرنامج التشغيل من خلال مستودع خاص من Maven. يشتمل المستودع على ملفات Project Object Model (.pom) لحزمة SDK وJavaScript. لإضافة Driver SDK إلى تطبيقك:

  1. أضِف التبعية التالية إلى إعدادات 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.

لتثبيت المكوّن الإضافي وتخزين مفتاح واجهة برمجة التطبيقات:

  1. افتح ملف 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")
        }
    }
    
  2. افتح ملف build.gradle على مستوى التطبيق وأضِف الرمز التالي إلى العنصر plugins.

    رائع

    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
    

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. إذا كنت تستخدم "استوديو Android"، عليك مزامنة مشروعك مع Gradle.

  4. افتح local.properties في الدليل على مستوى مشروعك، ثم أضِف الرمز التالي. استبدِل YOUR_API_KEY بمفتاح واجهة برمجة التطبيقات.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. في ملف 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):

  1. يمكنك الحصول على عنصر 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
        }
      },
    )
    
  2. أنشئ كائن 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()
    
  3. استخدِم الكائن DriverContext لتهيئة *DriverApi.

    لغة Java

    RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
    

    Kotlin

    val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
    
  4. يمكنك الحصول على 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.