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

يمكنك استخدام Driver SDK لتوفير تنقّل وتتبُّع محسّنَين في تطبيق "رحلتك" و"مستوى تقدّم الطلب". توفر Driver SDK تحديثات لموقع المركبة ومهامها لحلول Fleet Solutions (الرحلات والتسليمات) عند الطلب.

تُبقي حزمة Driver SDK خدمات Fleet Engine والخدمات المخصّصة لديك على دراية بموقع المركبة وحالتها. على سبيل المثال، يمكن أن تكون المركبة ONLINE أو OFFLINE، ويتغيّر الموقع الجغرافي للمركبة مع تقدّم الرحلة.

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

يجب أن يعمل الجهاز الجوّال بالإصدار 6.0 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات) أو إصدار أحدث.

ضبط التبعيات والإنشاء

يتوفّر الإصدار 4.99 والإصدارات الأحدث من Driver 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 أو اختَر مشروعًا حاليًا لاستخدامه مع حزمة تطوير البرامج (SDK) لخدمة Drive. انتظر بضع دقائق حتى يصبح المشروع الجديد مرئيًا على Google Cloud Console.

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

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

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

تتوفّر حزمة Driver SDK في مستودع Google Maven. يتضمن المستودع ملفات نموذج كائن المشروع (pom) لحزمة SDK وJavadocs. لإضافة 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>
    
  2. تعتمد حزمة تطوير البرامج (SDK) للسائق على حزمة تطوير البرامج (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>

أدرِج الإحالات الناجحة المطلوبة في تطبيقك.

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

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

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

التبعيات

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

-dontwarn com.google.**
-dontwarn okio.**

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

جارٍ إعداد حزمة تطوير البرامج (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) الخاصة بالسائقين من Drive الحصول على النسخة الافتراضية 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

ونظرًا لأنّ حزمة Driver 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 ليتمكّن من الاتصال بالخادم. يمكنك الاطّلاع على هذه المقالة للحصول على مزيد من المعلومات حول العمل باستخدام طبقة المقابس الآمنة (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.