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

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

ל-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 ואילך.

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

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

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

  1. יוצרים פרויקט חדש במסוף Google Cloud או בוחרים פרויקט קיים לשימוש עם Consumer 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.

הוספת Consumer SDK לאפליקציה שלך

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

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

פרטי הרישיונות מופיעים בקובץ "Third_party_Licenses.txt" בקובץ ה-AAR שאוחזר.

במאמר https://developers.google.com/android/guides/opensource מוסבר איך לכלול הודעות בקוד פתוח.

אימות SDK של צרכן

ה-SDK לצרכן מספק אימות באמצעות אסימוני אינטרנט מסוג JSON. אסימון אינטרנט מסוג JSON (JWT) הוא אסימון גישה מסוג JSON-base שמספק הצהרה אחת או יותר על שירות. לדוגמה, שרת יכול ליצור אסימון שההצהרה שלו היא 'מחובר כאדמין' ולספק אותה ללקוח. לאחר מכן הלקוח יוכל להשתמש באסימון הזה כדי להוכיח שהוא מחובר כאדמין.

Consumer SDK משתמש ב-JSON Web Token שסופק על ידי האפליקציה כדי לתקשר עם Fleet Engine. מידע נוסף זמין במאמר אימות והרשאה של מנוע חיפוש (Fleet Engine).

אסימון ההרשאה חייב לכלול הצהרת tripid:TRIP_ID בכותרת authorization של האסימון, כאשר TRIP_ID הוא מזהה הנסיעה. כך ל-SDK של הצרכן יש גישה לפרטי הנסיעה, כולל מיקום הרכב, המסלול וזמן ההגעה המשוער.

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

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

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

הקריאה החוזרת (callback) של אסימון ההרשאה מציינת איזה אסימון שירות נדרש לשירות 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. מידע נוסף על יצירת הפרויקט זמין במדריך למשתמש של Flet 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
}

הפעלת ה-SDK של מפות Google כדי לבקש כלי לעיבוד מועדף

Consumer SDK v2.0.0 תומך ב-Maps SDK ל-Android מגרסה 18.1.0 ואילך. הוא תומך בבקשות שמציינות את כלי הרינדור המועדף למפות Google. לפרטים, קראו את המאמר כלי ליצירת מפות חדש(הצטרפות).

הוספה של ה-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>

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

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

פתרון מובנה ל-Android SDK לצרכנים: Autocamera

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

ConsumerController

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

הגדרה של שיתוף נסיעות

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

  1. רושמים listener על אובייקט TripModel כדי לקבל פרטים על הנסיעה, כמו זמן ההגעה המשוער (ETA) והמרחק שצריך לעבור ברכב לפני ההגעה.

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

למידע נוסף קראו את המאמר טיפול בשגיאות של Consumer SDK.