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

يمكنك استخدام "حزمة تطوير البرامج (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:

  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</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.

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

  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>

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

إذا كنت تستخدم "حزمة تطوير البرامج (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:

  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 كاستثناءات مؤقتة ما لم تحدث بشكل متكرر. بعد عدد من المحاولات، ستفترض حزمة 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.