بدء استخدام حزمة تطوير البرامج (SDK) للمستهلكين لنظام التشغيل Android

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

نظرًا لأن حزمة Consumer SDK تتميز ببنية نموذجية، يمكنك استخدام أجزاء واجهة برمجة التطبيقات التي تريد استخدامها لتطبيقك الخاص ودمجها مع واجهات برمجة التطبيقات الخاصة بك، وخدمات الخلفية التي يوفرها Fleet Engine، بالإضافة إلى واجهات برمجة التطبيقات الخاصة بمنصة خرائط Google.

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

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

تكوين الإصدار والتبعيات

يتوفّر الإصدار 1.99.0 والإصدارات الأحدث من حزمة تطوير البرامج (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>

تكوين المشروع

لاستخدام حزمة تطوير البرامج (SDK) الخاصة بالمستهلكين لنظام التشغيل Android، يجب أن يستهدف تطبيقك الإصدار 23 من minSdkVersion أو الإصدارات الأحدث.

لتشغيل تطبيق تم إنشاؤه باستخدام حزمة تطوير البرامج (SDK) للمستهلكين، يجب تثبيت خدمات Google Play على جهاز Android.

إعداد مشروع التطوير

لإعداد مشروع التطوير والحصول على مفتاح واجهة برمجة تطبيقات للمشروع على Google Cloud Console:

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

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

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

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

تتوفّر "حزمة تطوير البرامج (SDK) للمستهلكين" من خلال مستودع Maven خاص. يتضمّن المستودع ملفات نموذج كائن المشروع (pom.) الخاصة بحزمة SDK وJavadocs. لإضافة حزمة تطوير البرامج (SDK) للمستهلكين إلى تطبيقك، يُرجى اتّباع الخطوات التالية:

  1. اضبط بيئتك للوصول إلى مستودع Maven المضيف كما هو موضّح في القسم السابق.

    إذا تم تعريف إعدادات إدارة التبعية المركزية في settings.gradle، يمكنك إيقافها على النحو التالي.

    • إزالة مجموعة الرموز التالية في settings.gradle:

      import org.gradle.api.initialization.resolve.RepositoriesMode
      dependencyResolutionManagement {
          repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
          repositories {
              google()
              mavenCentral()
          }
      }
      
  2. أضِف التبعية التالية إلى إعدادات Gradle أو Maven، واستبدِل العنصر النائب VERSION_NUMBER بالإصدار المطلوب من حزمة تطوير البرامج (SDK) للمستهلكين.

    Gradle

    أضِف ما يلي إلى build.gradle:

    dependencies {
      ...
      implementation 'com.google.android.libraries.mapsplatform.transportation:transportation-consumer:VERSION_NUMBER'
    }
    

    Maven

    أضِف ما يلي إلى pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-consumer</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  3. تعتمد حزمة تطوير البرامج (SDK) الخاصة بالمستهلك على حزمة تطوير البرامج (SDK) للخرائط. يتم ضبط هذه الاعتمادية بطريقة تتيح له عدم تحديد إصدار حزمة تطوير البرامج (SDK) للخرائط بشكل واضح في ملف إعداد الإصدار كما يلي، عندما يتم إصدار إصدار جديد من حزمة تطوير البرامج (SDK) للخرائط، ستستمر حزمة تطوير البرامج (SDK) للمستهلكين في استخدام الحد الأدنى المطلوب من إصدار حزمة تطوير البرامج (SDK) للخرائط.

    Gradle

    أضِف ما يلي إلى build.gradle:

    dependencies {
      ...
      implementation 'com.google.android.gms:play-services-maps:18.1.0'
    }
    

    Maven

    أضِف ما يلي إلى pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.gms</groupId>
        <artifactId>play-services-maps</artifactId>
        <version>18.1.0</version>
      </dependency>
    </dependencies>
    

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

بعد إضافة حزمة تطوير البرامج (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.consumerapidemo">
    <uses-permission android:name="android.permission.ACCESS_FINE_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 حول كيفية تضمين إشعارات البرامج المفتوحة المصدر.

مصادقة حزمة تطوير البرامج (SDK) للمستهلك

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

تستخدم حزمة تطوير البرامج (SDK) الخاصة بالمستهلك رمز JSON المميّز للويب الذي يوفّره التطبيق للتواصل مع Fleet Engine. يُرجى الاطّلاع على مصادقة وتفويض مجموعة المركبات للحصول على مزيد من المعلومات.

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

عمليات استدعاء الرمز المميّز للويب بتنسيق JSON

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

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

يحدّد معاودة الاتصال بالرمز المميز للتفويض الرمز المميز للخدمة المطلوب لخدمة TripService. وهي توفّر أيضًا سمة tripId المطلوبة للسياق.

يوضح مثال الرمز التالي كيفية تنفيذ استدعاء الرمز المميز للتفويض.

Java

class JsonAuthTokenFactory implements AuthTokenFactory {

  private static final String TOKEN_URL =
      "https://yourauthserver.example/token";

  private static class CachedToken {
    String tokenValue;
    long expiryTimeMs;
    String tripId;
  }

  private CachedToken token;

  /*
  * This method is called on a background thread. Blocking is OK. However, be
  * aware that no information can be obtained from Fleet Engine until this
  * method returns.
  */
  @Override
  public String getToken(AuthTokenContext context) {
    // If there is no existing token or token has expired, go get a new one.
    String tripId = context.getTripId();
    if (tripId == null) {
      throw new RuntimeException("Trip ID is missing from AuthTokenContext");
    }
    if (token == null || System.currentTimeMillis() > token.expiryTimeMs ||
        !tripId.equals(token.tripId)) {
      token = fetchNewToken(tripId);
    }
    return token.tokenValue;
  }

  private static CachedToken fetchNewToken(String tripId) {
    String url = TOKEN_URL + "/" + tripId;
    CachedToken token = new CachedToken();

    try (Reader r = new InputStreamReader(new URL(url).openStream())) {
      com.google.gson.JsonObject obj
          = com.google.gson.JsonParser.parseReader(r).getAsJsonObject();

      token.tokenValue = obj.get("ServiceToken").getAsString();
      token.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 5 minutes from that time.
      */
      token.expiryTimeMs -= 5 * 60 * 1000;
    } catch (IOException e) {
      /*
      * It's OK to throw exceptions here. The error listeners will receive the
      * error thrown here.
      */
      throw new RuntimeException("Could not get auth token", e);
    }
    token.tripId = tripId;

    return token;
  }
}

Kotlin

class JsonAuthTokenFactory : AuthTokenFactory() {

  private var token: CachedToken? = null

  /*
  * This method is called on a background thread. Blocking is OK. However, be
  * aware that no information can be obtained from Fleet Engine until this
  * method returns.
  */
  override fun getToken(context: AuthTokenContext): String {
    // If there is no existing token or token has expired, go get a new one.
    val tripId = 
      context.getTripId() ?: 
        throw RuntimeException("Trip ID is missing from AuthTokenContext")

    if (token == null || System.currentTimeMillis() > token.expiryTimeMs ||
        tripId != token.tripId) {
      token = fetchNewToken(tripId)
    }

    return token.tokenValue
  }

  class CachedToken(
    var tokenValue: String? = "", 
    var expiryTimeMs: Long = 0,
    var tripId: String? = "",
  )

  private companion object {
    const val TOKEN_URL = "https://yourauthserver.example/token"

    fun fetchNewToken(tripId: String) {
      val url = "$TOKEN_URL/$tripId"
      val token = CachedToken()

      try {
        val reader = InputStreamReader(URL(url).openStream())

        reader.use {
          val obj = com.google.gson.JsonParser.parseReader(r).getAsJsonObject()

          token.tokenValue = obj.get("ServiceToken").getAsString()
          token.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 5 minutes from that time.
          */
          token.expiryTimeMs -= 5 * 60 * 1000
        }
      } catch (e: IOException) {
        /*
        * It's OK to throw exceptions here. The error listeners will receive the
        * error thrown here.
        */
        throw RuntimeException("Could not get auth token", e)
      }

      token.tripId = tripId

      return token
    }
  }
}

إعداد واجهة برمجة التطبيقات

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

الحصول على مثيل "ConsumerApi"

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

providerId هو رقم تعريف المشروع الخاص بمشروعك على Google Cloud. يمكنك الاطّلاع على دليل مستخدم Fleet Engine للحصول على مزيد من المعلومات حول إنشاء المشروع.

يجب أن ينفِّذ تطبيقك AuthTokenFactory كما هو موضّح في مصادقة حزمة تطوير البرامج (SDK) للمستهلك.

Java

Task<ConsumerApi> consumerApiTask = ConsumerApi.initialize(
    this, "myProviderId", authTokenFactory);

consumerApiTask.addOnSuccessListener(
  consumerApi -> this.consumerApi = consumerApi);

Kotlin

val consumerApiTask =
  ConsumerApi.initialize(this, "myProviderId", authTokenFactory)

consumerApiTask?.addOnSuccessListener { consumerApi: ConsumerApi ->
  this@YourActivity.consumerApi = consumerApi
}

حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" وبرامج عرض الخرائط

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

إصدار حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" التوافق مع أحدث إصدار من العارض دعم العارض القديم العارض التلقائي
الإصدار 18.1.0 والإصدارات الأقدم نعم نعم الإصدار القديم*
V18.2.0 نعم نعم الأحدث

* مع طرح عارض الخرائط الجديد، سيتم إعداد "الإصدار الأحدث" تلقائيًا.

إضافة حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" كملحق

Gradle

أضِف ما يلي إلى build.gradle:

dependencies {
  //...
  implementation "com.google.android.gms:play-services-maps:VERSION_NUMBER"
}

Maven

أضِف ما يلي إلى pom.xml:

 <dependencies>
   ...
   <dependency>
     <groupId>com.google.android.gms</groupId>
     <artifactId>play-services-maps</artifactId>
     <version>18.1.0</version>
   </dependency>
 </dependencies>

إعداد حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" قبل إعداد حزمة تطوير البرامج (SDK) الخاصة بالمستهلك

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

java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  initViews();

  MapsInitializer.initialize(getApplicationContext(), Renderer.LATEST,
      new OnMapsSdkInitializedCallback() {
        @Override
        public void onMapsSdkInitialized(Renderer renderer) {
          switch (renderer) {
            case LATEST:
              Log.i("maps_renderer", "LATEST renderer");
              break;
            case LEGACY:
              Log.i("maps_renderer", "LEGACY renderer");
              break;
          }

          initializeConsumerSdk();
        }
      });
}

Kotlin

fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.main)
  initViews()

  MapsInitializer.initialize(
    getApplicationContext(), Renderer.LATEST,
    object : OnMapsSdkInitializedCallback() {
      fun onMapsSdkInitialized(renderer: Renderer?) {
        when (renderer) {
          LATEST -> Log.i("maps_renderer", "LATEST renderer")
          LEGACY -> Log.i("maps_renderer", "LEGACY renderer")
        }
        initializeConsumerSdk()
      }
    })
  }

إنشاء واجهة المستخدم

يمكنك استخدام ConsumerMapFragment أو ConsumerMapView لإنشاء واجهة المستخدم لتطبيقك. يتيح لك ConsumerMapFragment تحديد الخريطة باستخدام Fragment، بينما يتيح لك ConsumerMapView استخدام View. تتشابه وظائف مشاركة الرحلات في كل من ConsumerMapView وConsumerMapFragment، لذا يمكنك اختيار وظيفة استنادًا إلى ما إذا كان View أو Fragment هو الأفضل لتطبيقك.

إتاحة استخدام عناصر واجهة برمجة التطبيقات 19 (KitKat) وVector القابل للرسم

إذا كان تصميم تطبيقك يتطلب التوافق مع أجهزة واجهة برمجة التطبيقات 19 (KitKat) والعناصر المتجهة القابلة للرسم، أضِف الرمز التالي إلى سجلّ "نشاطك". يؤدي هذا الرمز إلى توسيع AppCompatActivity لاستخدام عناصر Vector القابلة للرسم في حزمة تطوير البرامج (SDK) الخاصة بالمستهلك.

Java

// ...
import android.support.v7.app.AppCompatActivity;

// ...

public class ConsumerTestActivity extends AppCompatActivity {
  // ...
}

Kotlin

// ...
import android.support.v7.app.AppCompatActivity

// ...

class ConsumerTestActivity : AppCompatActivity() {
  // ...
}

إضافة جزء الخريطة أو طريقة العرض

يمكنك إنشاء الخريطة لعرض مشاركة الرحلة إما في جزء Android أو في طريقة العرض، والتي يتم تحديدها في ملف XML لتنسيق التطبيق (الموجود في /res/layout). يوفّر الجزء (أو العرض) بعد ذلك إمكانية الوصول إلى خريطة مشاركة الرحلة، التي يمكن لتطبيقك الوصول إليها وتعديلها. توفّر الخريطة أيضًا اسمًا معرِّفًا لـ "ConsumerController"، يتيح لتطبيقك التحكّم في تجربة مشاركة الرحلة وتخصيصها.

مشاركة الخريطة ووحدة التحكّم في الرحلة

يمكنك تحديد خريطة مشاركة الرحلة إما كجزء (باستخدام ConsumerMapFragment) أو كعرض (باستخدام ConsumerMapView)، كما هو موضّح في مثال الرمز التالي. بعد ذلك، يجب استدعاء طريقة onCreate() getConsumerGoogleMapAsync(callback)، مما يؤدي إلى عرض ConsumerGoogleMap بشكل غير متزامن في معاودة الاتصال. يمكنك بعد ذلك استخدام ConsumerGoogleMap لعرض مشاركة الرحلة، ويمكن تعديله حسب الحاجة من خلال تطبيقك.

ConsumerMapFragment

يمكنك تعريف الجزء في ملف XML لتخطيط التطبيق، كما هو موضّح في مثال الرمز التالي.

<fragment
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.google.android.libraries.mapsplatform.transportation.consumer.view.ConsumerMapFragment"
    android:id="@+id/consumer_map_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

يجب أن يأتي استدعاء getConsumerGoogleMapAsync() من الطريقة onCreate().

Java

public class SampleAppActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {

    // Find the ConsumerMapFragment.
    ConsumerMapFragment consumerMapFragment =
        (ConsumerMapFragment) fragmentManager.findFragmentById(R.id.consumer_map_fragment);

    // Initiate the callback that returns the map.
    if (consumerMapFragment != null) {
      consumerMapFragment.getConsumerGoogleMapAsync(
          new ConsumerMapReadyCallback() {
            // The map returned in the callback is used to access the ConsumerController.
            @Override
            public void onConsumerMapReady(@NonNull ConsumerGoogleMap consumerGoogleMap) {
              ConsumerController consumerController = consumerGoogleMap.getConsumerController();
            }
          });
    }
  }

}

Kotlin

class SampleAppActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    // Find the ConsumerMapFragment.
    val consumerMapFragment =
      fragmentManager.findFragmentById(R.id.consumer_map_fragment) as ConsumerMapFragment

    consumerMapFragment.getConsumerGoogleMapAsync(
      object : ConsumerMapReadyCallback() {
        override fun onConsumerMapReady(consumerGoogleMap: ConsumerGoogleMap) {
          val consumerController = consumerGoogleMap.getConsumerController()!!
        }
      }
    )
  }
}
ConsumerMapView

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

<com.google.android.libraries.mapsplatform.transportation.consumer.view.ConsumerMapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/consumer_map_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

يجب أن تكون المكالمة إلى getConsumerGoogleMapAsync() من onCreate(). بالإضافة إلى مَعلمة معاودة الاتصال، تتطلب تلك الدالة النشاط الذي يتضمّن النشاط أو الجزء الذي يتضمّن السمة، وسمة GoogleMapOptions (التي يمكن أن تكون فارغة)، مع تضمين سمات الضبط للسمة MapView. يجب أن تكون الفئة الأساسية الخاصة بالنشاط أو الجزء إما FragmentActivity أو Fragment للدعم (على التوالي)، لأنّها تتيح الوصول إلى مراحل النشاط.

Java

public class SampleAppActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ConsumerMapView mapView = findViewById(R.id.consumer_map_view);

    if (mapView != null) {
      mapView.getConsumerGoogleMapAsync(
          new ConsumerMapReadyCallback() {
            // The map returned in the callback is used to access the ConsumerController.
            @Override
            public void onConsumerMapReady(@NonNull ConsumerGoogleMap consumerGoogleMap) {
              ConsumerController consumerController = consumerGoogleMap.getConsumerController();
            }
          }, this, null);
    }
  }

}

Kotlin

class SampleAppActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    val mapView = findViewById(R.id.consumer_map_view) as ConsumerMapView

    mapView.getConsumerGoogleMapAsync(
      object : ConsumerMapReadyCallback() {
        // The map returned in the callback is used to access the ConsumerController.
        override fun onConsumerMapReady(consumerGoogleMap: ConsumerGoogleMap) {
          val consumerController = consumerGoogleMap.getConsumerController()!!
        }
      },
      /* fragmentActivity= */ this,
      /* googleMapOptions= */ null,
    )
  }
}

يتطابق MapView في جزء مع المثال أعلاه لـ MapView في النشاط، غير أنّ الجزء يضخّم التنسيق الذي يتضمّن MapView في طريقة onCreateView() للجزء.

Java

public class MapViewInFragment extends Fragment {

  @Override
  public View onCreateView(
      @NonNull LayoutInflater layoutInflater,
      @Nullable ViewGroup viewGroup,
      @Nullable Bundle bundle) {
    return layoutInflater.inflate(R.layout.consumer_map_view, viewGroup, false);
  }

}

Kotlin

class MapViewInFragment : Fragment() {
  override fun onCreateView(
    layoutInflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View {
    return layoutInflater.inflate(R.layout.consumer_map_view, viewGroup, false)
  }
}

ضبط التكبير أو التصغير في الكاميرا للتركيز في رحلة

يعمل الزر "موقعي" التلقائي المُدمج في حزمة تطوير البرامج (SDK) للخرائط على تركيز الكاميرا على موقع الجهاز.

إذا كانت هناك جلسة "مشاركة الرحلة" نشطة، قد تحتاج إلى توسيط الكاميرا للتركيز على الرحلة بدلاً من موقع الجهاز.

حزمة تطوير البرامج (SDK) الخاصة بالمستهلكين لنظام التشغيل Android المُدمَجة: Auto Camera

للسماح لك بالتركيز على الرحلة بدلاً من موقع الجهاز، توفّر حزمة "SDK للمستهلكين" ميزة "كاميرا تلقائية" يتم تفعيلها تلقائيًا. يتم تكبير الكاميرا للتركيز على مسار مشاركة الرحلة ونقطة الطريق التالية للرحلة.

AutoCamera

تخصيص سلوك الكاميرا

إذا أردت التحكّم بشكل أكبر في سلوك الكاميرا، يمكنك إيقاف الكاميرا التلقائية أو تفعيلها باستخدام ConsumerController.setAutoCameraEnabled().

تعرض ConsumerController.getCameraUpdate() حدود الكاميرا المقترَحة في هذه اللحظة. يمكنك بعد ذلك تقديم CameraUpdate كوسيطة إلى GoogleMap.moveCamera() أو GoogleMap.animateCamera().

الوصول إلى الخرائط ومشاركة الرحلات

لدعم مشاركة الرحلات والتفاعل مع الخرائط في تطبيقك، يجب الوصول إلى ConsumerGoogleMap وConsumerController. يتم عرض ConsumerMapFragment وConsumerMapView بشكل غير متزامن ConsumerGoogleMap باللغة ConsumerMapReadyCallback. يمكن إرجاع المشتريات من خلال "ConsumerGoogleMap" بسعر ConsumerController ابتداءً من getConsumerController(). يمكنك الوصول إلى ConsumerGoogleMap وConsumerController على النحو التالي.

Java

private ConsumerGoogleMap consumerGoogleMap;
private ConsumerController consumerController;
private ConsumerMapView consumerMapView;

consumerMapView.getConsumerGoogleMapAsync(
    new ConsumerMapReadyCallback() {
      @Override
      public void onConsumerMapReady(@NonNull ConsumerGoogleMap consumerMap) {
        consumerGoogleMap = consumerMap;
        consumerController = consumerMap.getConsumerController();
      }
    },
    this, null);

Kotlin

var consumerGoogleMap: ConsumerGoogleMap
var consumerController: ConsumerController
val consumerMapView = findViewById(R.id.consumer_map_view) as ConsumerMapView

consumerMapView.getConsumerGoogleMapAsync(
  object : ConsumerMapReadyCallback() {
    override fun onConsumerMapReady(consumerMap: ConsumerGoogleMap) {
      consumerGoogleMap = consumerMap
      consumerController = consumerMap.getConsumerController()
    },
    /* fragmentActivity= */ this,
    /* googleMapOptions= */ null,
  }
)

ConsumerGoogleMap

وConsumerGoogleMap هي فئة تضمين للفئة GoogleMap. فهي تزوّد تطبيقك بإمكانية التفاعل مع الخريطة باستخدام واجهة برمجة تطبيقات تعادل GoogleMap. يتيح استخدام خريطة المستهلك لتطبيقك ومشاركة الرحلات التفاعل بسلاسة مع نفس خريطة Google الأساسية. على سبيل المثال، لا تسمح السمة GoogleMap إلا بتسجيل معاودة اتصال واحدة، بينما تتيح السمة ConsumerGoogleMap عمليات معاودة الاتصال المسجَّلة المزدوجة. تتيح عمليات معاودة الاتصال هذه لتطبيقك وخدمة مشاركة الرحلة تسجيل معاودة الاتصال، وهي تُسمّى بشكل تسلسلي.

ConsumerController

توفّر ConsumerController إمكانية الوصول إلى وظائف مشاركة الرحلات، مثل مراقبة الرحلات والتحكّم في حالة الرحلة وضبط المواقع الجغرافية.

إعداد ميزة "مشاركة الرحلة"

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

  1. يمكنك تسجيل أداة استماع على عنصر TripModel للحصول على تفاصيل حول الرحلة مثل الوقت المقدّر للوصول والمسافة التي يجب أن تقطعها المركبة قبل الوصول.

    Java

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    String tripName = ...;
    TripModelManager tripModelManager = consumerApi.getTripModelManager();
    TripModel tripModel = tripModelManager.getTripModel(tripName);
    
    // Create a JourneySharingSession instance based on the TripModel.
    JourneySharingSession session = JourneySharingSession.createInstance(tripModel);
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session);
    
    // Register for trip update events.
    tripModel.registerTripCallback(new TripModelCallback() {
      @Override
      public void onTripETAToNextWaypointUpdated(
          TripInfo tripInfo, @Nullable Long timestampMillis) {
        // ...
      }
    
      @Override
      public void onTripActiveRouteRemainingDistanceUpdated(
          TripInfo tripInfo, @Nullable Integer distanceMeters) {
        // ...
      }
    
      // ...
    });
    

    Kotlin

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    val tripName = "tripName"
    val tripModelManager = consumerApi.getTripModelManager()
    val tripModel = tripModelManager.getTripModel(tripName)
    
    // Create a JourneySharingSession instance based on the TripModel.
    val session = JourneySharingSession.createInstance(tripModel)
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session)
    
    // Register for trip update events.
    tripModel.registerTripCallback(
      object : TripModelCallback() {
        override fun onTripETAToNextWaypointUpdated(
          tripInfo: TripInfo,
          timestampMillis: Long?,
        ) {
          // ...
        }
    
        override fun onTripActiveRouteRemainingDistanceUpdated(
          tripInfo: TripInfo,
          distanceMeters: Int?,
        ) {
          // ...
        }
    
      // ...
    })
    
  2. ضبط رحلتك باستخدام "TripModelOptions"

    Java

    // Set refresh interval to 2 seconds.
    TripModelOptions tripOptions =
        TripModelOptions.builder().setRefreshIntervalMillis(2000).build();
    tripModel.setTripModelOptions(tripOptions);
    

    Kotlin

    // Set refresh interval to 2 seconds.
    val tripOptions = TripModelOptions.builder().setRefreshIntervalMillis(2000).build()
    tripModel.setTripModelOptions(tripOptions)
    

إيقاف مشاركة الرحلة

تأكَّد من إيقاف مشاركة الرحلة عند عدم الحاجة إليها، مثلاً عند إتلاف نشاط المضيف. يؤدي إيقاف مشاركة الرحلة أيضًا إلى إيقاف طلبات الشبكة إلى Fleet Engine ومنع تسرُّب الذاكرة.

يوضح الرمز النموذجي التالي كيفية إيقاف مشاركة الرحلة.

Java

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

  @Override
  protected void onDestroy() {
    super.onDestroy();

    if (journeySharingSession != null) {
      journeySharingSession.stop();
    }
  }
}

Kotlin

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

التعامل مع أخطاء الرحلة

تعرِض الطريقة onTripRefreshError الأخطاء التي تحدث أثناء تتبُّع الرحلة. تتّبع عملية الربط لأخطاء حزمة تطوير البرامج (SDK) الخاصة بالمستهلكين إرشادات HTTP/RPC نفسها التي تم إنشاؤها من أجل Google Cloud Platform. تشمل الأخطاء الشائعة التي تظهر أثناء مراقبة الرحلة ما يلي:

HTTP متوسط عائد النقرة الوصف
400 INVALID_ARGUMENT حدّد العميل اسم رحلة غير صالح. يجب أن يتّبع اسم الرحلة التنسيق providers/{provider_id}/trips/{trip_id}. يجب أن يكون provider_id هو رقم تعريف مشروع Cloud الذي يملكه مقدّم الخدمة.
401 غير مصدَّق عليها لم تتم مصادقة الطلب بسبب وجود رمز JWT مميز غير صالح. سيحدث هذا الخطأ في حال توقيع رمز JWT المميز بدون معرّف الرحلة أو انتهاء صلاحية الرمز المميز JWT.
403 PERMISSION_DENIED العميل لا يملك إذنًا كافيًا. يحدث هذا الخطأ إذا كان الرمز المميز لـ JWT غير صالح، أو لم يكن لدى العميل إذن، أو لم يتم تفعيل واجهة برمجة التطبيقات لمشروع العميل. قد يكون رمز JWT غير متوفّر أو قد تم توقيع الرمز المميّز باستخدام معرّف رحلة لا يتطابق مع معرّف الرحلة المطلوب.
429 RESOURCE_EXHAUSTED تصبح حصة الموارد صفرًا أو أن معدل الزيارات يتجاوز الحد المسموح به.
503 UNAVAILABLE الخدمة غير متاحة. عادةً ما يكون الخادم معطلاً.
504 DEADLINE_EXCEEDED تجاوزت الموعد النهائي للطلب. ولن يحدث ذلك إلا إذا عيّن المتصل موعدًا نهائيًا أقصر من الموعد النهائي الافتراضي للطريقة (أي أنّ الموعد النهائي المطلوب غير كافٍ لتمكين الخادم من معالجة الطلب) ولم ينتهِ الطلب بعد الموعد النهائي.

لمزيد من المعلومات، يُرجى الاطّلاع على معالجة أخطاء حزمة تطوير البرامج (SDK) للمستهلك.