תחילת העבודה עם SDK SDK ל-Android

תוכלו להשתמש ב-SDK לצרכנים כדי ליצור ולהפעיל אפליקציה בסיסית לצרכנים שמשולבת עם שירותים לקצה העורפי של 'נסיעות ומשלוחים' על פי דרישה. אתם יכולים ליצור אפליקציה של נסיעה והתקדמות בהזמנה שיכולה להציג נסיעה פעילה, להגיב לעדכוני נסיעה ולטפל בשגיאות בנסיעה.

מכיוון של- Consumer SDK יש ארכיטקטורה מודולרית, תוכלו להשתמש בחלקי ה-API שבהם אתם רוצים להשתמש באפליקציה הספציפית שלכם ולשלב אותם בממשקי API משלכם, בשירותים לקצה העורפי שמסופקים על ידי Fleet Engine, וגם בממשקי API של הפלטפורמה של מפות Google.

דרישות מערכת מינימליות

במכשיר הנייד צריכה לפעול מערכת Android בגרסה 6.0 (API ברמה 23) ואילך.

הגדרת build ויחסי תלות

גרסאות 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, האפליקציה צריכה לטרגט ל-minSdkVersion בגרסה 23 ואילך.

כדי להריץ אפליקציה שנוצרה באמצעות ה-SDK לצרכנים, צריך להתקין במכשיר ה-Android את Google Play Services.

הגדרת פרויקט פיתוח

כדי להגדיר את פרויקט הפיתוח ולקבל מפתח API לפרויקט במסוף Google Cloud:

  1. יוצרים פרויקט חדש במסוף Google Cloud או בוחרים פרויקט קיים לשימוש עם ה-SDK לצרכנים. ממתינים כמה דקות עד שהפרויקט החדש מופיע במסוף Google Cloud.

  2. כדי להריץ את אפליקציית ההדגמה, לפרויקט שלכם צריכה להיות גישה ל-SDK של מפות Google ל-Android. במסוף Google Cloud, בוחרים באפשרות APIs & Services > Library ואז מחפשים את ה-SDK של מפות Google ל-Android ומפעילים אותו.

  3. כדי לקבל מפתח API לפרויקט, בוחרים באפשרות APIs & Services > Credentials > Create credentials > API key. במאמר קבלת מפתח API תוכלו לקרוא מידע נוסף על קבלת מפתח API.

הוספת ה-SDK לצרכנים לאפליקציה

ה-SDK לצרכנים זמין דרך מאגר Maven פרטי. המאגר כולל את קובצי Project Object Model (.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, ומחליפים את ה-placeholder הזה 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 של מפות Google. התלות הזו מוגדרת כך שאם גרסת ה-SDK של מפות Google לא מוגדרת במפורש בקובץ תצורת build, כמו בדוגמה הבאה, כשתושק גרסה חדשה של מפות Google, ה-SDK לצרכנים ממשיך להשתמש בגרסה המינימלית הנתמכת של SDK של מפות Google הנדרשת על ידה.

    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>
    

הוספה של מפתח ה-API לאפליקציה

אחרי שמוסיפים לאפליקציה את ה-SDK לצרכנים, מוסיפים את מפתח ה-API לאפליקציה. עליכם להשתמש במפתח ה-API של הפרויקט שקיבלתם כשהגדרתם את פרויקט הפיתוח.

בקטע הזה מוסבר איך לאחסן את מפתח ה-API כדי שהאפליקציה תוכל להפנות אליו בצורה מאובטחת יותר. אל תבדקו את מפתח ה-API במערכת ניהול הגרסאות שלכם. צריך לאחסן אותו בקובץ local.properties, שנמצא בתיקיית השורש של הפרויקט. למידע נוסף על הקובץ local.properties ראו קובצי מאפייני Gradle.

כדי לייעל את המשימה הזו, אפשר להשתמש בפלאגין של Secrets Gradle ל-Android.

כדי להתקין את הפלאגין ולאחסן את מפתח ה-API:

  1. פותחים את קובץ build.gradle ברמה הבסיסית (root) ומוסיפים את הקוד הבא לרכיב 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 Studio, אתם יכולים לסנכרן את הפרויקט עם Gradle.

  4. פותחים את local.properties בספרייה ברמת הפרויקט ומוסיפים את הקוד הבא. מחליפים את YOUR_API_KEY במפתח ה-API שלכם.

    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 לצרכנים באפליקציה שלכם, אתם צריכים לכלול את טקסט השיוך (Attribution) ורישיונות קוד פתוח כחלק מהקטע 'הודעות משפטיות' של האפליקציה. מומלץ לכלול את הקרדיטים האלה כאפשרות עצמאית בתפריט או כחלק מפריט בתפריט מידע כללי.

ניתן למצוא את פרטי הרישיונות בקובץ '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 גישה לפרטי הנסיעה, כולל המיקום של הרכב, המסלול וזמן ההגעה המשוער.

קריאה חוזרת (callback) של אסימון אינטרנט מסוג JSON

במהלך האתחול, ה-SDK של הצרכן רושם באפליקציה קריאה חוזרת (callback) של אסימון הרשאה. ה-SDK קורא לאפליקציה לקבל אסימון לכל בקשות הרשת שמחייבות הרשאה.

מומלץ מאוד שאסימון ההרשאה של הטמעת הקריאה החוזרת (callback) יהיה זמין במטמון, ולרענן אותם רק אחרי המועד של expiry. האסימונים צריכים להיות עם תפוגה של שעה אחת.

הקריאה החוזרת של אסימון ההרשאה מציינת איזה אסימון שירות צריך בשביל השירות TripService. הוא גם מספק את tripId הנדרש בשביל ההקשר.

הקוד לדוגמה הבא מדגים איך מטמיעים קריאה חוזרת (callback) לאסימון הרשאה.

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
    }
  }
}

אתחול ה-API

לפני שאתם מבצעים את ההליכים האלה, אנחנו מניחים שהפעלתם את השירותים המתאימים ואת ה-SDK לצרכנים.

אחזור של המופע ConsumerApi

כדי להשתמש ב- Consumer SDK, האפליקציה שלכם צריכה לאתחל את ConsumerApi באופן אסינכרוני. ה-API הוא סינגלטון. שיטת האתחול לוקחת AuthTokenFactory. המפעל מייצר למשתמש אסימוני JWT חדשים כשיש צורך.

providerId הוא מזהה הפרויקט של הפרויקט ב-Google Cloud. מידע נוסף על יצירת הפרויקט זמין במדריך למשתמש של כלל המכשירים בארגון.

באפליקציה שלכם צריך להטמיע את 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
}

SDK של מפות Google וכלים לעיבוד מפות

Consumer SDK גרסה 2.x.x תומך ב-SDK של מפות Google ל-Android גרסה 18.1.0 ואילך. הטבלה שבהמשך מציגה סיכום של כלי הרינדור שמוגדר כברירת מחדל לפי גרסת ה-SDK של מפות Google ויכולת התמיכה של שני כלי הרינדור. אבל אם אתם צריכים להשתמש בכלי הישן לרינדור, תוכלו לציין אותו באופן מפורש באמצעות MapsInitializer.initialize().

גרסת SDK של מפות Google תמיכה בכלי לרינדור העדכני ביותר תמיכה בכלי לרינדור מדור קודם כלי לעיבוד שמוגדר כברירת מחדל
גרסה 18.1.0 ומטה כן כן דור קודם*
V18.2.0 כן כן פורסמו לאחרונה

* לאחר ההשקה של הכלי החדש לעיבוד מפות Google, הכלי האחרון לרינדור יוגדר כברירת מחדל.

הוספת SDK של מפות כתלות

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>

אתחול ה-SDK של מפות Google לפני הפעלת ה-SDK של הצרכן

במחלקה Application או במחלקה Activity של ההפעלה, קוראים ל-MapsInitializer.initialize() ומחכים לתוצאה של בקשת הרינדור לפני שמפעילים את Consumer 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.

הוספת תמיכה ל-API 19 (KitKat) ולפריטים גרפיים וקטוריים

אם עיצוב האפליקציה דורש תמיכה במכשירי API 19 (KitKat) ובפריטים גרפיים וקטוריים, צריך להוסיף את הקוד הבא לפעילות. הקוד הזה מרחיבים את AppCompatActivity לשימוש בפריטים גרפיים וקטוריים ב-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), כפי שמוצג בדוגמת הקוד הבאה. ה-method 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() צריכה להגיע מה-method 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 (שיכול להיות null), שמכיל את מאפייני ההגדרות של 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 ב-method 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 של מפות Google ממרכזת את המצלמה במיקום המכשיר.

אם יש סשן פעיל של שיתוף מסלול, כדאי למרכז את המצלמה כדי להתמקד בתהליך במקום במיקום המכשיר.

פתרון 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 היא מחלקה מסוג wrapper של המחלקה GoogleMap. היא מאפשרת לאפליקציה לבצע אינטראקציה עם המפה באמצעות API מקביל ל-GoogleMap. השימוש במפת הצרכנים מאפשר לאפליקציה ולשיתוף הנסיעות ליצור אינטראקציה חלקה עם אותה מפה בסיסית של Google. לדוגמה, הפקודה GoogleMap מאפשרת רישום של קריאה חוזרת רק פעם אחת, אבל ConsumerGoogleMap תומך בקריאות חוזרות (callbacks) רשומות כפולות. הקריאות החוזרות האלה מאפשרות לאפליקציה ולשיתוף הנסיעה כדי לרשום קריאות חוזרות, שנקראות ברצף.

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 לא תקין, אם ללקוח אין הרשאה או שה-API לא מופעל בפרויקט הלקוח. יכול להיות שאסימון ה-JWT חסר או שהוא חתום עם מזהה נסיעה שלא תואם למזהה הנסיעה המבוקש.
429 RESOURCE_EXHAUSTED מכסת המשאבים היא אפס או שקצב תעבורת הנתונים חורג מהמגבלה.
503 UNAVAILABLE השירות לא זמין. בדרך כלל השרת מושבת.
504 DEADLINE_EXCEEDED המועד האחרון של הבקשה עבר. זה יקרה רק אם המתקשר יגדיר מועד אחרון שקצר ממועד ברירת המחדל שנקבע כברירת מחדל לשיטה (כלומר, המועד האחרון המבוקש לא מספיק לטיפול בבקשה), והבקשה לא הסתיימה במסגרת המועד האחרון.

מידע נוסף זמין במאמר טיפול בשגיאות ב-SDK לצרכנים.