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

الحد الأدنى لمتطلبات النظام

يجب أن يعمل الجهاز الجوّال بالإصدار 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:

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

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

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

إضافة حزمة تطوير البرامج (SDK) لبرنامج التشغيل إلى تطبيقك

تتوفّر حزمة Driver SDK في مستودع Google Maven. يتضمّن المستودع ملفات نموذج كائن المشروع (pom.) الخاصة بحزمة SDK وJavadocs. لإضافة حزمة تطوير البرامج (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.driver</groupId>
        <artifactId>transportation-driver</artifactId>
        <version>[VERSION_NUMBER]</version>
      </dependency>
    </dependencies>
    
  2. تعتمد حزمة تطوير البرامج (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. اتبع هذا الإجراء لتثبيت المكوّن الإضافي Secrets Gradle والتخزين الآمن لمفتاح واجهة برمجة التطبيقات.

  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. مزامنة مشروعك مع 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>

إدراج عمليات تحديد المصدر المطلوبة في تطبيقك

إذا كنت تستخدم "حزمة تطوير البرامج (SDK) لبرنامج التشغيل" في تطبيقك، عليك تضمين نص الإحالة وتراخيص البرامج المفتوحة المصدر كجزء من قسم الإشعارات القانونية في تطبيقك. ومن الأفضل تضمين عمليات الإحالة كعنصر قائمة مستقل أو كجزء من عنصر قائمة لمحة.

يمكن العثور على معلومات التراخيص في ملف "third_party_ Licenses.txt" في ملف AAR غير المؤرشف.

يمكنك الرجوع إلى https://developers.google.com/android/guides/opensource حول كيفية تضمين إشعارات البرامج المفتوحة المصدر.

التبعيات

تستخدم حزمة Driver SDK gRPC للاتصال بخادم Fleet Engine. إذا لم تكن تستخدم gRPC بالفعل، فقد تحتاج إلى تعريف التبعيات التالية:

dependencies {
    implementation 'io.grpc:grpc-android:1.12.0'
    implementation 'io.grpc:grpc-okhttp:1.12.0'
}

وبدون هذه التبعيات، قد تواجه حزمة Driver SDK أخطاء في وقت التشغيل أثناء محاولة الاتصال بخادم Fleet Engine.

إذا كنت تستخدم ProGuard لتحسين إصداراتك، فقد تحتاج إلى إضافة الأسطر التالية إلى ملف إعداد ProGuard:

-dontwarn com.google.**
-dontwarn io.grpc.**
-dontwarn okio.**

الحد الأدنى لمستوى واجهة برمجة التطبيقات المتوافق هو 23.

إعداد حزمة تطوير البرامج (SDK)

يجب إدخال رقم تعريف موفّر (يكون عادةً رقم تعريف مشروع Google Cloud) لإعداد عنصر DriverContext. لمزيد من التفاصيل حول إعداد مشروع Google Cloud، يُرجى الاطّلاع على المصادقة والتفويض.

قبل استخدام حزمة تطوير البرامج (SDK) لبرنامج التشغيل، عليك أولاً إعداد حزمة SDK للتنقّل. لإعداد حزمة SDK:

  1. الحصول على كائن 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;
          }
        }
    );
    
  2. أنشِئ عنصر DriverContext، مع تعبئة الحقول المطلوبة.

    DriverContext driverContext = DriverContext.builder(application)
        .setProviderId(providerId)
        .setVehicleId(vehicleId)
        .setAuthTokenFactory(authTokenFactory)
        .setNavigator(navigator)
        .setRoadSnappedLocationProvider(
            NavigationApi.getRoadSnappedLocationProvider(application))
        .build();
    
  3. استخدِم الكائن DriverContext لإعداد *DriverApi.

    DeliveryDriverApi driverApi = DeliveryDriverApi.createInstance(driverContext);
    
  4. يمكنك الحصول على DeliveryVehicleReporter من كائن واجهة برمجة التطبيقات. (تمتد DeliveryVehicleReporter إلى NavigationVehicleReporter.)

    DeliveryVehicleReporter vehicleReporter = driverApi.getDeliveryVehicleReporter();
    

المصادقة مع AuthTokenFactory

عندما تنشئ حزمة Driver SDK تحديثات الموقع الجغرافي، يجب أن ترسل هذه التحديثات إلى خادم Fleet Engine. لمصادقة هذه الطلبات، تطلب "حزمة تطوير البرامج (SDK) لبرنامج التشغيل" من مثيل AuthTokenFactory الذي يوفّره المتصل. المصنع مسؤول عن إنشاء رموز المصادقة المميزة في وقت تحديث الموقع.

وتعتمد كيفية إنشاء الرموز المميزة بدقة على حالة كل مطور. مع ذلك، من المحتمل أن تحتاج عملية التنفيذ إلى:

  • جلب رمز مصادقة مميز، ربما بتنسيق JSON، من خادم HTTPS
  • تحليل الرمز المميز وتخزينه مؤقتًا
  • إعادة تحميل الرمز المميّز عند انتهاء صلاحيته

لمعرفة تفاصيل الرموز المميّزة التي يتوقعها خادم Fleet Engine، يُرجى الاطّلاع على إنشاء رمز JSON المميّز للويب (JWT) للتفويض.

في ما يلي شرح أساسي لـ AuthTokenFactory:

class JsonAuthTokenFactory implements AuthTokenFactory {
  private String vehicleServiceToken;  // 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(vehicleId);
    }
    if (ServiceType.VEHICLE.equals(authTokenContext.getServiceType)) {
      return vehicleServiceToken;
    } else {
      throw new RuntimeException("Unsupported ServiceType: " + authTokenContext.getServiceType());
    }
  }

  private void fetchNewToken(String vehicleId) {
    String url = "https://yourauthserver.example/token/" + vehicleId;

    try (Reader r = new InputStreamReader(new URL(url).openStream())) {
      com.google.gson.JsonObject obj
          = com.google.gson.JsonParser.parseReader(r).getAsJsonObject();
      vehicleServiceToken = obj.get("VehicleServiceToken").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);
    }
  }
}

يستخدم هذا التنفيذ تحديدًا عميل Java HTTP المضمن لجلب رمز مميز بتنسيق JSON من خادم مصادقة المطوّر. تم حفظ الرمز لإعادة استخدامه. وتتم إعادة جلب الرمز المميز إذا كان في غضون 10 دقائق من وقت انتهاء صلاحيته.

قد تختلف طريقة التنفيذ بالنسبة إليك، مثل استخدام سلسلة محادثات في الخلفية لإعادة تحميل الرموز المميّزة.

يتم التعامل مع الاستثناءات في AuthTokenFactory كاستثناءات مؤقتة ما لم تحدث بشكل متكرر. بعد إجراء عدد من المحاولات، تفترض حزمة Driver SDK أن الخطأ دائم وتتوقف عن محاولة إرسال التحديثات.

الإبلاغ عن الحالة والأخطاء في "StatusListener"

بما أنّ "حزمة تطوير البرامج (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.
  }
}

ملاحظات حول طبقة المقابس الآمنة/بروتوكول أمان طبقة النقل (TLS)

يستخدم تطبيق Driver SDK داخليًا طبقة المقابس الآمنة (SSL)/بروتوكول أمان طبقة النقل (TLS) للاتصال الآمن بخادم Fleet Engine. وقد تتطلّب الإصدارات السابقة من Android (الإصدار 23 أو الإصدارات الأقدم من واجهة برمجة التطبيقات) رمز تصحيح SecurityProvider للاتصال بالخادم. لمزيد من المعلومات حول العمل باستخدام طبقة المقابس الآمنة (SSL) في Android، راجِع موفّر خدمات Google للأجهزة الجوّالة (GMS). تحتوي المقالة أيضًا على عيّنات تعليمات برمجية لتصحيح إعدادات موفِّر الأمان.

تفعيل تحديثات الموقع الجغرافي

بعد الحصول على مثيل *VehicleReporter، ستكون عملية تفعيل تعديلات الموقع الجغرافي واضحة:

DeliveryVehicleReporter reporter = ...;

reporter.enableLocationTracking();

يتم إرسال تحديثات الموقع الجغرافي على فترات زمنية منتظمة، إن أمكن. يشير كل تحديث للموقع أيضًا إلى أن المركبة متصلة بالإنترنت.

بشكل افتراضي، يبلغ الفاصل الزمني لإعداد التقارير 10 ثوانٍ. يمكنك تغيير الفاصل الزمني لإعداد التقارير باستخدام reporter.setLocationReportingInterval(long, TimeUnit) يبلغ الحدّ الأدنى للفاصل الزمني المسموح به للتحديث 5 ثوانٍ. قد تؤدي التحديثات الأكثر تكرارًا إلى بطء الطلبات والأخطاء.

إيقاف تحديثات الموقع الجغرافي

عند انتهاء وردية السائق، يمكنك إيقاف تعديلات الموقع الجغرافي من خلال الاتصال برقم DeliveryVehicleReporter.disableLocationTracking.

حالات استخدام النماذج الموثوقة

يوضّح هذا القسم كيفية استخدام حزمة Driver SDK لتنفيذ حالات الاستخدام الشائعة عند استخدام النموذج الموثوق به.

إنشاء مركبة

يمكنك إنشاء مركبة من حزمة Driver SDK.

قبل إنشاء مركبة، تأكَّد من إعداد Delivery Driver API. يجب إنشاء رقم تعريف المركبة مع رقم تعريف المركبة ورقم تعريف موفّر الخدمة المستخدمَين أثناء إعداد "حزمة تطوير البرامج (SDK) لبرنامج التشغيل". ثم أنشئ المركبة كما هو موضح في المثال التالي:

DeliveryDriverApi api = DeliveryDriverApi.getInstance();
DeliveryVehicleManager vehicleManager = api.getDeliveryVehicleManager();
try {
  DeliveryVehicle vehicle = vehicleManager.createVehicle().get();
  // Handle CreateVehicleRequest DeliveryVehicle response.
} catch (Exception e) {
  // Handle CreateVehicleRequest error.
}

إنشاء مهمة استلام الشحنة

يمكنك إنشاء مهمة استلام الشحنة من "حزمة تطوير البرامج (SDK) لبرنامج التشغيل".

قبل إنشاء مهمة، تأكَّد من إعداد Delivery Driver API. يجب إنشاء المهمة باستخدام رقم تعريف الموفّر المحدد أثناء إعداد حزمة تطوير البرامج (SDK) لبرنامج التشغيل. بعد ذلك، أنشئ مهمة الاستلام من الشحنة كما هو موضح في المثال التالي. للحصول على معلومات حول معرّفات المهام، يُرجى الاطّلاع على أمثلة على معرّفات المهام.

static final String TASK_ID = "task-8241890"; // Avoid auto-incrementing IDs.

DeliveryDriverApi api = DeliveryDriverApi.getInstance();
DeliveryTaskManager taskManager = api.getDeliveryTaskManager();
CreateDeliveryTaskRequest request = CreateDeliveryTaskRequest.builder(TASK_ID)
   .setPlannedWaypoint(Waypoint.builder().setLatLng(-6.195139, 106.820826).build())
   .setTaskDurationSeconds(2 * 60)
   .setParentId("my-tracking-id")
   .setTaskType(TaskType.DELIVERY_PICKUP)
   .build();

try {
   DeliveryTask task = taskManager.createTask(request).get();
   // Handle CreateTaskRequest DeliveryTask response.
} catch (Exception e)  {
   // Handle CreateTaskRequest error.
}

إنشاء مهمة تسليم شحنة

يمكنك إنشاء مهمة تسليم شحنة من "حزمة تطوير البرامج (SDK) لبرنامج التشغيل".

قبل إنشاء مهمة، تأكَّد من إعداد Delivery Driver API. بعد ذلك، أنشِئ مهمة تسليم الشحنة على النحو الموضّح في المثال التالي. للحصول على معلومات حول معرّفات المهام، يُرجى الاطّلاع على أمثلة على معرّفات المهام.

static final String TASK_ID = "task-8241890"; // Avoid auto-incrementing IDs.

DeliveryDriverApi api = DeliveryDriverApi.getInstance();
DeliveryTaskManager taskManager = api.getDeliveryTaskManager();
CreateDeliveryTaskRequest request = CreateDeliveryTaskRequest.builder(TASK_ID)
   .setPlannedWaypoint(Waypoint.builder().setLatLng(-6.195139, 106.820826).build())
   .setTaskDurationSeconds(2 * 60)
   .setParentId("my-tracking-id")
   .setTaskType(TaskType.DELIVERY_DELIVERY)
   .build();
try {
   DeliveryTask task = taskManager.createTask(request).get();
   // Handle CreateTaskRequest DeliveryTask response.
} catch (Exception e)  {
   // Handle CreateTaskRequest error.
}

عدم التوفّر المجدوَل

يمكنك إنشاء مهمة من حزمة تطوير البرامج (SDK) الخاصة بالسائق تشير إلى عدم التوفّر (على سبيل المثال، لأعطال السائق أو إعادة ملء السيارة بالوقود). يجب ألا تتضمن مهمة عدم التوفّر المجدولة معرّف تتبع. يمكنك تحديد موقع جغرافي بشكل اختياري.

قبل إنشاء مهمة، تأكَّد من إعداد Delivery Driver API. بعد ذلك، أنشئ مهمة "عدم التوفّر" كما هو موضّح في المثال التالي. للحصول على معلومات حول معرّفات المهام، يُرجى الاطّلاع على أمثلة على معرّفات المهام.

static final String TASK_ID = "task-8241890"; // Avoid auto-incrementing IDs.

DeliveryDriverApi api = DeliveryDriverApi.getInstance();
DeliveryTaskManager taskManager = api.getDeliveryTaskManager();
CreateDeliveryTaskRequest request = CreateDeliveryTaskRequest.builder(TASK_ID)
   .setTaskDurationSeconds(2 * 60) // Duration or location (or both) must be provided for a BREAK task.
   .setTaskType(TaskType.UNAVAILABLE)
   .build();
try {
   DeliveryTask task = taskManager.createTask(request).get();
   // Handle CreateTaskRequest DeliveryTask response.
} catch (Exception e)  {
   // Handle CreateTaskRequest error.
}

محطّات توقّف مجدولة

يمكنك إنشاء مهمة إيقاف مجدوَلة إما من حزمة تطوير البرامج (SDK) لبرنامج التشغيل. قد لا تتضمن مهمة الإيقاف المجدولة رقم تعريف تتبع.

قبل إنشاء مهمة، تأكَّد من إعداد Delivery Driver API. بعد ذلك، أنشئ مهمة الإيقاف المُجدوَلة كما هو موضّح في المثال التالي. للحصول على معلومات حول معرّفات المهام، يُرجى الاطّلاع على أمثلة على معرّفات المهام.

    static final String TASK_ID = "task-8241890"; //  Avoid auto-incrementing IDs.

    DeliveryDriverApi api = DeliveryDriverApi.getInstance();
    DeliveryTaskManager taskManager = api.getDeliveryTaskManager();
    CreateDeliveryTaskRequest request = CreateDeliveryTaskRequest.builder(TASK_ID)
       .setPlannedWaypoint(Waypoint.builder().setLatLng(-6.195139, 106.820826).build())
       .setTaskDurationSeconds(2 * 60)
       .setTaskType(TaskType.DELIVERY_SCHEDULED_STOP)
       .build();
    try {
       DeliveryTask task = taskManager.createTask(request).get();
       // Handle CreateTaskRequest DeliveryTask response.
    } catch (Exception e)  {
       // Handle CreateTaskRequest error.
    }

تعديل ترتيب المهام

يمكنك تعديل ترتيب تنفيذ المهام المخصّصة للمركبة من "حزمة تطوير البرامج (SDK) الخاصة ببرنامج التشغيل".

يؤدي تحديث ترتيب المهام أيضًا إلى تعيين المهام للمركبة إذا لم يتم إسنادها سابقًا لمركبة. كما يغلق المهام التي تم تعيينها سابقًا لمركبة وتم استبعادها من الطلب المحدث. يؤدي تعيين مهمة لمركبة مختلفة إذا تم تعيينها من قبل لمركبة أخرى إلى حدوث خطأ. قبل تعيين مهمة للمركبة الجديدة، أغلق المهمة الحالية ثم أنشئ مهمة جديدة.

يمكنك تعديل ترتيب المهام في أي وقت.

قبل تحديث ترتيب المهمة للمركبة، تأكد من أن المركبة والمهام قد تم إنشاؤها بالفعل في Fleet Engine. ثم قم بتحديث ترتيب المهمة للمركبة كما هو موضح في المثال التالي.

    DeliveryDriverApi api = DeliveryDriverApi.getInstance();
    DeliveryVehicleReporter reporter = api.getDeliveryVehicleReporter();
    try {
       List<VehicleStop> stops = reporter.setVehicleStops(
         ImmutableList.of(
             VehicleStop.builder()
                 .setVehicleStopState(VehicleStopState.ARRIVED)
                 .setWaypoint(Waypoint.builder().setLatLng(37.1749, 122.412).build())
                 .setTasks(ImmutableList.of(task1)) // Previously created DeliveryTask in Fleet Engine.
                 .build(),
             VehicleStop.builder()
                 .setVehicleStopState(VehicleStopState.NEW) // The current vehicle stop.
                 .setWaypoint(Waypoint.builder().setLatLng(37.7749, 122.4194).build())
                 .setTasks(ImmutableList.of(task2)) // Previously created DeliveryTask in Fleet Engine.
                 .build(),
             VehicleStop.builder()
                 .setVehicleStopState(VehicleStopState.NEW)
                 .setWaypoint(Waypoint.builder().setLatLng(37.3382, 121.8863).build())
                 .setTasks(ImmutableList.of(task3, task4)) // Previously created DeliveryTasks in Fleet Engine.
                 .build())).get();
       // Successfully updated vehicle stops in Fleet Engine. Returns the successfully set VehicleStops.
    } catch (Exception e)  {
       // Failed to update vehicle stops in Fleet Engine. Setting VehicleStops must be attempted again after resolving
       // errors.
    }

قد يحدث استثناء قد يمنع إجراء تحديث للحالة الداخلية لحزمة تطوير البرامج (SDK) لبرنامج التشغيل. إذا حدث هذا، قم بحل المشكلة ثم الاتصال بـ setVehicleStops مرة أخرى حتى تتم المكالمة بنجاح.

يمكن أن تشمل المشاكل المحتملة ما يلي:

  • إنّ نقاط إيقاف السيارة المحدّدة لا تتّبع نمطًا صالحًا. يمكن أن تكون أول VehicleStop فقط في أي من حالة نقطة OnHub: NEW أو ENROUTE أو ARRIVED. يجب أن تكون "محطات إيقاف المركبات" بعد المحطة الحالية في "حالة إيقاف السيارة" الجديدة.

  • إنّ المهام غير متوفّرة أو أنّها تنتمي إلى مركبة مختلفة.

  • المركبة غير موجودة.

مركبة في طريقها إلى المحطة التالية

يجب إبلاغ فريق Fleet Engine عند مغادرة مركبة للمحطة وعند بدء التنقّل. يمكنك إشعار Fleet Engine من خلال حزمة Driver SDK.

قبل إبلاغ Fleet Engine بأن مركبة غادرت من المحطة، تأكد من إنشاء محطات التوقف وضبطها. ثم قم بإخطار Fleet Engine بمغادرة المركبة كما هو موضح في المثال التالي.

    DeliveryDriverApi api = DeliveryDriverApi.getInstance();
    DeliveryVehicleReporter reporter = api.getDeliveryVehicleReporter();
    reporter.enableLocationTracking(); // Location tracking must be enabled.

    // Create Vehicle, VehicleStops, and DeliveryTasks.
    // Set VehicleStops on Vehicle.

    navigator.setDestination(vehicleStop.getWaypoint());
    try {
       List<VehicleStop> updatedStops = reporter.enrouteToNextStop().get();
       // Successfully updated vehicle stops in Fleet Engine. Returns the set VehicleStops, with the first
       // VehicleStop updated to ENROUTE state.
    } catch (Exception e)  {
       // Failed to update vehicle stops in Fleet Engine. Updating VehicleStops must be attempted again
       // after resolving errors.
    }

قد يحدث استثناء قد يمنع إجراء تحديث للحالة الداخلية لحزمة تطوير البرامج (SDK) لبرنامج التشغيل. وفي حال حدوث ذلك، يجب حل المشكلة ثم الاتصال بـ enrouteToNextStop مرة أخرى إلى أن تتم معالجة المشكلة.

يمكن أن تشمل المشاكل المحتملة ما يلي:

  • لم يتم ضبط VehicleStops متبقية في حزمة تطوير البرامج (SDK) لبرنامج التشغيل.

وصول مركبة إلى محطة

يجب إرسال إشعار إلى مجموعة المركبات عند وصول مركبة إلى محطة. يمكنك إبلاغ Fleet Engine من خلال حزمة Driver SDK.

قبل إبلاغ Fleet Engine بوصول مركبة إلى محطة معيّنة، تأكّد من أنّه قد تم ضبط محطات إيقاف المركبة. بعد ذلك، أبلغ Fleet Engine بوصول المركبة إلى المحطة كما هو موضح في المثال التالي.

DeliveryDriverApi api = DeliveryDriverApi.getInstance();
DeliveryVehicleReporter reporter = api.getDeliveryVehicleReporter();
reporter.enableLocationTracking(); // Location tracking must be enabled.

// Create Vehicle, VehicleStops, and DeliveryTasks.
// Set VehicleStops on Vehicle.
// Mark ENROUTE to VehicleStop and start guidance using Navigator.

try {
   List<VehicleStop> updatedStopsArrived = reporter.arrivedAtStop().get();
   // Successfully updated vehicle stops in Fleet Engine. Returns the set VehicleStops, with the first
   // VehicleStop updated to ARRIVED state.
   navigator.clearDestinations();
} catch (Exception e)  {
   // Failed to update vehicle stops in Fleet Engine. Updating VehicleStops must be attempted again
   // after resolving errors.
}

قد يحدث استثناء قد يمنع إجراء تحديث للحالة الداخلية لحزمة تطوير البرامج (SDK) لبرنامج التشغيل. وفي حال حدوث ذلك، يجب حلّ المشكلة ثم الاتصال بخدمة arrivedAtStop مرة أخرى إلى أن يتم التعامل معها بنجاح.

قد تشمل المشاكل المحتملة ما يلي:

  • لم يتم ضبط VehicleStops متبقية في حزمة تطوير البرامج (SDK) لبرنامج التشغيل.

تكمل مركبة محطة

يجب إعلام Fleet Engine عند اكتمال توقّف أي مركبة. يؤدي هذا الإشعار إلى ضبط جميع المهام المرتبطة بالمحطة على حالة "مغلق". يمكنك إبلاغ Fleet Engine من خلال حزمة Driver SDK.

أبلغ Fleet Engine بأنّ المركبة قد أكملت عملية إيقاف السيارة وفقًا لما هو موضّح في المثال التالي.

    DeliveryDriverApi api = DeliveryDriverApi.getInstance();
    DeliveryVehicleReporter reporter = api.getDeliveryVehicleReporter();
    reporter.enableLocationTracking(); // Location tracking must be enabled.

    // After completing the tasks at the VehicleStop, remove it from the
    // the current list of VehicleStops.

    try {
       List<VehicleStop> updatedStopsCompleted = reporter.completedStop().get();
       // Successfully updated vehicle stops in Fleet Engine. All tasks on the completed stop are set to CLOSED.
       // Returns the set VehicleStops, with the completed VehicleStop removed from the remaining list.
    } catch (Exception e)  {
       // Failed to update vehicle stops in Fleet Engine. Updating VehicleStops must be attempted again
       // after resolving errors.
    }

قد يحدث استثناء قد يمنع إجراء تحديث للحالة الداخلية لحزمة تطوير البرامج (SDK) لبرنامج التشغيل. وفي حال حدوث ذلك، يجب حلّ المشكلة ثم الاتصال بخدمة completedStop مرة أخرى إلى أن يتم التعامل معها بنجاح.

يمكن أن تشمل المشاكل المحتملة ما يلي:

  • لم يتم ضبط VehicleStops متبقية في حزمة تطوير البرامج (SDK) لبرنامج التشغيل.

إغلاق مهمة

لإغلاق مهمة تم تعيينها لمركبة، إما إبلاغ Fleet Engine بأن المركبة قد أكملت المحطة التي تحدث فيها المهمة، أو أزِلها من قائمة محطات التوقف. لإجراء ذلك، يمكنك ضبط قائمة محطات التوقف المتبقية للمركبة كما هو الحال عند تعديل ترتيب المهام لمركبة.

إذا لم يتم تعيين مركبة إلى مهمة بعد، ويجب إغلاقها، يمكنك تعديل المهمة لتصبح "مغلقة". ومع ذلك، لا يمكنك إعادة فتح مهمة تم إغلاقها.

لا يشير إغلاق المهمة إلى النجاح أو الفشل. يشير إلى أن المهمة لم تعد قيد التقدم. بالنسبة لتتبع الشحن، من المهم الإشارة إلى النتيجة الفعلية لمهمة ما حتى يمكن عرض نتيجة التسليم.

يجب تعيين مهمة لمركبة حتى تتمكن من استخدام حزمة تطوير البرامج (SDK) الخاصة ببرنامج التشغيل لإغلاق المهمة. لإغلاق مهمة تم تعيينها لمركبة، قم بإعلام Fleet Engine بأن المركبة قد أكملت المحطة التي تتم فيها المهمة.

يمكنك بدلاً من ذلك تعديل ترتيب المهام للمركبة التي تم إسناد المهمة إليها، ثم إزالة المهمة من قائمة محطات التوقف.

تحديد نتيجة المهمة وموقع النتيجة

لا يشير إغلاق المهمة إلى النجاح أو الفشل. يشير إلى أن المهمة لم تعد قيد التقدم. بالنسبة لتتبع الشحن، من المهم الإشارة إلى النتيجة الفعلية للمهمة حتى يمكن عرض نتيجة التسليم، ومن ثم تكون هناك فوترة مناسبة للخدمات. بمجرد التعيين، لا يمكنك تغيير نتيجة المهمة. ولكن يمكنك تعديل وقت نتيجة المهمة وموقع نتيجة المهمة بعد تحديدها.

يمكن ضبط نتائج المهام في الحالة "مغلقة" على "SUCCEEDED" أو "تعذّر الإجراء". يتقاضى Fleet Engine مهام التسليم فقط بالحالة "SUCCEEDED".

عند وضع علامة على نتيجة مهمة، يملأ Fleet Engine تلقائيًا موقع نتائج المهمة بآخر موقع معروف للمركبة. يمكنك تجاوز هذا السلوك.

يوضِّح لك المثال التالي كيفية استخدام حزمة تطوير البرامج (SDK) لبرنامج التشغيل لتحديد نتيجة المهمة وطابعها الزمني. لا يمكنك ضبط موقع نتيجة المهمة باستخدام حزمة تطوير البرامج (SDK) لبرنامج التشغيل.

    static final String TASK_ID = "task-8241890";

    DeliveryDriverApi api = DeliveryDriverApi.getInstance();
    DeliveryTaskManager taskManager = api.getDeliveryTaskManager();

    // Updating an existing DeliveryTask which is already CLOSED. Manually
    // setting TaskOutcomeLocation with Driver SDK is not supported at this time.
    UpdateDeliveryTaskRequest req = UpdateDeliveryTaskRequest.builder(TASK_ID)
        .setTaskOutcome(TaskOutcome.SUCCEEDED)
        .setTaskOutcomeTimestamp(now()) // Timestamp in milliseconds.
        .build();

    try {
       DeliveryTask updatedTask = taskManager.updateTask(req);
       // Handle UpdateTaskRequest DeliveryTask response.
    } catch (Exception e)  {
       // Handle UpdateTaskRequest error.
    }

البحث عن مركبة

يمكنك البحث عن مركبة من خلال حزمة تطوير البرامج (SDK) الخاصة بالسائق. قبل البحث عن مركبة، تأكَّد من إعداد Delivery Driver API. يمكنك بعد ذلك البحث عن المركبة كما هو موضح في المثال التالي.

    DeliveryDriverApi api = DeliveryDriverApi.getInstance();
    DeliveryVehicleManager vehicleManager = api.getDeliveryVehicleManager();
    try {
       DeliveryVehicle vehicle = vehicleManager.getVehicle().get();
       // Handle GetVehicleRequest DeliveryVehicle response.
    } catch (Exception e)  {
       // Handle GetVehicleRequest error.
    }

ولا يمكن أن يبحث "DeliveryVehicleManager" إلا في DeliveryVehicle عن معرّف المركبة الذي تم تقديمه أثناء إعداد Delivery Driver API.