การเริ่มต้นใช้งาน Consumer SDK สําหรับ Android

คุณสามารถใช้ Consumer SDK เพื่อสร้างและเรียกใช้แอปสำหรับผู้บริโภคขั้นพื้นฐานที่ผสานรวมกับบริการแบ็กเอนด์ของโซลูชันการโดยสารและการนำส่งแบบออนดีมานด์ คุณสามารถสร้างแอปการเดินทางและความคืบหน้าของคำสั่งซื้อซึ่งแสดงการเดินทางที่ใช้งานอยู่ ตอบกลับการอัปเดตการเดินทาง และจัดการข้อผิดพลาดในการเดินทางได้

เนื่องจาก Consumer SDK มีสถาปัตยกรรมแบบแยกส่วน คุณจึงสามารถใช้ส่วนต่างๆ ของ API ที่คุณต้องการใช้สำหรับแอปเฉพาะและผสานรวมกับ API ของคุณเอง, บริการแบ็กเอนด์ที่ให้บริการโดย Fleet Engine และ API เพิ่มเติมสำหรับแพลตฟอร์ม Google Maps ได้

ข้อกำหนดขั้นต่ำของระบบ

อุปกรณ์เคลื่อนที่ต้องใช้ Android 6.0 (API ระดับ 23) ขึ้นไป

การกำหนดค่าบิลด์และการอ้างอิง

Consumer SDK เวอร์ชัน 1.99.0 ขึ้นไปมีให้ใช้งานผ่านทางที่เก็บ 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>

การกำหนดค่าโปรเจ็กต์

หากต้องการใช้ Consumer SDK สำหรับ Android แอปของคุณต้องกำหนดเป้าหมายเป็น minSdkVersion ระดับ 23 ขึ้นไป

หากต้องการเรียกใช้แอปที่สร้างด้วย Consumer SDK อุปกรณ์ Android ต้องติดตั้งบริการ Google Play ไว้

ตั้งค่าโปรเจ็กต์การพัฒนา

วิธีตั้งค่าโปรเจ็กต์การพัฒนาและรับคีย์ API สำหรับโปรเจ็กต์ใน Google Cloud Console มีดังนี้

  1. สร้างโปรเจ็กต์คอนโซล Google Cloud ใหม่หรือเลือกโปรเจ็กต์ที่มีอยู่เพื่อใช้กับ SDK ผู้บริโภค โปรดรอสักครู่จนกว่าโปรเจ็กต์ใหม่จะปรากฏใน Google Cloud Console

  2. เพื่อเรียกใช้แอปเดโม โปรเจ็กต์ต้องมีสิทธิ์เข้าถึง Maps SDK สำหรับ Android ใน Google Cloud Console ให้เลือก API และบริการ > ไลบรารี จากนั้นค้นหาและเปิดใช้ Maps SDK สำหรับ Android

  3. รับคีย์ API สำหรับโปรเจ็กต์โดยเลือก API และบริการ > ข้อมูลเข้าสู่ระบบ > สร้างข้อมูลเข้าสู่ระบบ > คีย์ API ดูข้อมูลเพิ่มเติมเกี่ยวกับการรับคีย์ API ได้ที่รับคีย์ API

เพิ่ม Consumer SDK ลงในแอป

Consumer SDK พร้อมให้ใช้งานผ่านที่เก็บ Maven ส่วนตัว ที่เก็บประกอบด้วยไฟล์ Project Object Model (.pom) และ Javadocs ของ SDK วิธีเพิ่ม Consumer SDK ลงในแอป

  1. ตั้งค่าสภาพแวดล้อมเพื่อเข้าถึงที่เก็บ Maven ของโฮสต์ตามที่อธิบายไว้ในส่วนก่อนหน้านี้

    หากคุณได้ประกาศการกำหนดค่าการจัดการทรัพยากร Dependency จากส่วนกลางไว้ใน settings.gradle ให้ปิดใช้ดังนี้

    • นำโค้ดบล็อกต่อไปนี้ใน settings.gradle ออก

      import org.gradle.api.initialization.resolve.RepositoriesMode
      dependencyResolutionManagement {
          repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
          repositories {
              google()
              mavenCentral()
          }
      }
      
  2. เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในการกำหนดค่า Gradle หรือ Maven ของคุณ แล้วแทนที่ตัวยึดตำแหน่ง VERSION_NUMBER สำหรับเวอร์ชัน Consumer 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. Consumer SDK ต้องใช้ Maps SDK ทรัพยากร Dependency นี้ได้รับการกำหนดค่าในลักษณะที่ไม่ได้กำหนดเวอร์ชันของ Maps SDK อย่างชัดเจนในไฟล์การกำหนดค่าบิลด์ดังตัวอย่างด้านล่าง เมื่อมีการเผยแพร่ Maps SDK เวอร์ชันใหม่ Consumer SDK จะยังคงใช้ Maps 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>
    

เพิ่มคีย์ API ลงในแอป

เมื่อเพิ่ม Consumer SDK ลงในแอปแล้ว ให้เพิ่มคีย์ API ลงในแอป คุณต้องใช้คีย์ API ของโปรเจ็กต์ที่ได้มาเมื่อตั้งค่าโปรเจ็กต์การพัฒนา

ส่วนนี้อธิบายวิธีจัดเก็บคีย์ API เพื่อให้แอปอ้างอิงคีย์ดังกล่าวได้อย่างปลอดภัยยิ่งขึ้น คุณไม่ควรตรวจสอบคีย์ API ในระบบควบคุมเวอร์ชัน ซึ่งควรเก็บไว้ในไฟล์ local.properties ซึ่งอยู่ในไดเรกทอรีรากของโปรเจ็กต์ ดูข้อมูลเพิ่มเติมเกี่ยวกับไฟล์ local.properties ได้ที่ไฟล์คุณสมบัติ Gradle

หากต้องการเพิ่มประสิทธิภาพงานนี้ คุณอาจใช้ปลั๊กอิน Secrets Gradle สำหรับ Android

วิธีติดตั้งปลั๊กอินและเก็บคีย์ API

  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 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 ที่สมบูรณ์สำหรับแอปตัวอย่าง

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

ใส่การระบุแหล่งที่มาที่จำเป็นลงในแอปของคุณ

หากใช้ Consumer SDK ในแอป คุณต้องใส่ข้อความระบุแหล่งที่มาและใบอนุญาตโอเพนซอร์สเป็นส่วนหนึ่งของส่วนประกาศทางกฎหมายของแอป วิธีที่ดีที่สุดคือรวมการระบุแหล่งที่มาเป็นรายการในเมนูอิสระหรือเป็นส่วนหนึ่งของรายการในเมนูเกี่ยวกับ

ข้อมูลใบอนุญาตจะอยู่ในไฟล์ "Third_party_licenses.txt" ในไฟล์ AAR ที่ยกเลิกการเก็บ

ดูวิธีใส่ประกาศโอเพนซอร์สได้ที่ https://developers.google.com/android/guides/opensource

การตรวจสอบสิทธิ์ SDK ของผู้บริโภค

Consumer SDK ให้การตรวจสอบสิทธิ์โดยใช้ JSON Web Token JSON Web Token (JWT) เป็นโทเค็นเพื่อการเข้าถึงของ JSON-base ที่มีการอ้างสิทธิ์อย่างน้อย 1 รายการในบริการต่างๆ ตัวอย่างเช่น เซิร์ฟเวอร์สามารถสร้างโทเค็นที่มีการอ้างสิทธิ์ว่า "เข้าสู่ระบบเป็นผู้ดูแลระบบ" และให้โทเค็นนั้นกับไคลเอ็นต์ จากนั้นไคลเอ็นต์จะใช้โทเค็นดังกล่าวเพื่อพิสูจน์ว่าโทเค็นเข้าสู่ระบบในฐานะผู้ดูแลระบบได้

Consumer SDK ใช้ JSON Web Token ที่แอปพลิเคชันมีให้เพื่อสื่อสารกับ Fleet Engine โปรดดูข้อมูลเพิ่มเติมที่การตรวจสอบสิทธิ์และการให้สิทธิ์ของ Flleet Engine

โทเค็นการให้สิทธิ์ต้องมีการอ้างสิทธิ์ tripid:TRIP_ID ในส่วนหัว authorization ของโทเค็น โดยที่ TRIP_ID คือรหัสการเดินทาง ซึ่งทำให้ SDK ผู้บริโภคเข้าถึงรายละเอียดการเดินทาง รวมถึงตำแหน่งของรถ เส้นทาง และเวลาถึงโดยประมาณได้

โค้ดเรียกกลับของ JSON Web Token

Consumer SDK จะบันทึกการเรียกกลับโทเค็นการให้สิทธิ์กับแอปพลิเคชันในระหว่างการเริ่มต้น SDK จะเรียกแอปพลิเคชันให้รับโทเค็นสำหรับคำขอเครือข่ายทั้งหมดที่ต้องมีการให้สิทธิ์

เราขอแนะนำเป็นอย่างยิ่งให้ใช้โทเค็นการให้สิทธิ์แคชการใช้งานโค้ดเรียกกลับและรีเฟรชโทเค็นดังกล่าวเฉพาะเมื่อเวลาผ่านไป expiry เท่านั้น โทเค็นควรออกเมื่อหมดอายุ 1 ชั่วโมง

โค้ดเรียกกลับของโทเค็นการให้สิทธิ์จะระบุว่าต้องใช้โทเค็นบริการใดสำหรับบริการ 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
    }
  }
}

เริ่มต้น API

ก่อนทำตามขั้นตอนเหล่านี้ เราจะถือว่าคุณได้เปิดใช้บริการที่เหมาะสมและ Consumer SDK แล้ว

รับอินสแตนซ์ ConsumerApi

หากต้องการใช้ SDK สำหรับผู้บริโภค แอปของคุณต้องเริ่มต้น ConsumerApi แบบไม่พร้อมกัน API เป็น Singleton วิธีเริ่มต้นจะใช้ 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
}

เริ่มต้น Maps SDK เพื่อขอตัวแสดงผลที่ต้องการ

Consumer SDK v2.0.0 รองรับ Maps SDK สำหรับ Android v18.1.0 ขึ้นไป รองรับคำขอที่ระบุตัวแสดงผล Google Maps ที่ต้องการ สำหรับรายละเอียด โปรดดูที่โปรแกรมแสดงแผนที่ใหม่(เลือกใช้)

เพิ่ม Maps SDK เป็นทรัพยากร Dependency

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>

เริ่มต้น Maps SDK ก่อนที่จะเริ่มต้น Consumer 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 เหมาะกับแอปพลิเคชันของคุณมากกว่า

เพิ่มการรองรับ API 19 (KitKat) และ Vector Drawables

หากการออกแบบแอปต้องการการรองรับอุปกรณ์ API 19 (KitKat) และอุปกรณ์เวกเตอร์ที่ถอนออกได้ ให้เพิ่มโค้ดต่อไปนี้ลงในกิจกรรมของคุณ รหัสนี้จะขยายไปถึง AppCompatActivity เพื่อใช้เวกเตอร์ที่ถอนออกได้ใน Consumer SDK

Java

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

// ...

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

Kotlin

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

// ...

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

เพิ่มมุมมองหรือส่วนย่อยของแผนที่

คุณสร้างแผนที่เพื่อแสดงการแชร์เส้นทางใน Fragment ของ Android หรือมุมมอง ซึ่งคุณกำหนดไว้ในไฟล์ XML ของเลย์เอาต์ของแอปพลิเคชัน (อยู่ใน /res/layout) จากนั้น Fragment (หรือมุมมอง) จะให้สิทธิ์เข้าถึงแผนที่ที่แชร์เส้นทาง ซึ่งแอปของคุณจะเข้าถึงและแก้ไขได้ แผนที่ยังมีแฮนเดิลให้ 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

มุมมองนี้สามารถใช้ใน Fragment หรือในกิจกรรมก็ได้ตามที่กำหนดไว้ในไฟล์ 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() นอกเหนือจากพารามิเตอร์โค้ดเรียกกลับ พารามิเตอร์นี้ต้องมีกิจกรรมหรือ Fragment ที่มี และ GoogleMapOptions (ซึ่งอาจเป็น Null) ซึ่งมีแอตทริบิวต์การกําหนดค่าสำหรับ MapView คลาสกิจกรรมหรือคลาสฐาน Fragment ต้องเป็น 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 ใน Fragment เหมือนกับตัวอย่างด้านบนสำหรับ MapView ในกิจกรรม เว้นแต่ว่า Fragment จะขยายเลย์เอาต์ที่รวม MapView ในเมธอด Fragment 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)
  }
}

ปรับการซูมของกล้องเพื่อโฟกัสการเดินทาง

ปุ่มตำแหน่งของฉันเริ่มต้นที่มีอยู่ใน Maps SDK จะทำให้กล้องอยู่ตรงกลางตำแหน่งอุปกรณ์

หากมีเซสชันการแชร์เส้นทางการท่องเว็บอยู่ คุณอาจต้องตั้งกล้องให้อยู่ตรงกลางเพื่อโฟกัสที่การเดินทาง ไม่ใช่ตำแหน่งของอุปกรณ์

SDK สำหรับผู้บริโภคสำหรับโซลูชันในตัวของ Android: Autocamera

Consumer SDK มอบฟีเจอร์ Auto Camera ที่เปิดใช้โดยค่าเริ่มต้นเพื่อให้คุณโฟกัสกับการใช้งานแทนตำแหน่งอุปกรณ์ กล้องจะซูมเพื่อโฟกัสที่เส้นทางที่แชร์การเดินทางและจุดอ้างอิงการเดินทางถัดไป

AutoCamera

การปรับแต่งลักษณะการทำงานของกล้อง

หากต้องการควบคุมลักษณะการทำงานของกล้องได้มากขึ้น คุณสามารถปิดหรือเปิดใช้ กล้องอัตโนมัติได้โดยใช้ ConsumerController.setAutoCameraEnabled()

ConsumerController.getCameraUpdate() จะแสดงขอบเขตกล้องที่แนะนำ ณ เวลานั้น จากนั้นคุณจะระบุ CameraUpdate นี้เป็นอาร์กิวเมนต์ให้กับ GoogleMap.moveCamera() หรือ GoogleMap.animateCamera() ได้

ใช้บริการร่วมเดินทางและแผนที่

คุณต้องมีสิทธิ์เข้าถึง ConsumerGoogleMap และ ConsumerController เพื่อรองรับบริการร่วมเดินทางและการโต้ตอบกับแผนที่ในแอปพลิเคชันของคุณ ConsumerMapFragment และ ConsumerMapView ทั้ง 2 ค่าจะแสดงผล 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 Maps ที่เกี่ยวข้องเดียวกันได้อย่างราบรื่น ตัวอย่างเช่น 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 จะแสดงข้อผิดพลาดที่เกิดขึ้นระหว่างการตรวจสอบการเดินทาง การแมปข้อผิดพลาด Consumer SDK เป็นไปตามหลักเกณฑ์ HTTP/RPC เดียวกันกับที่จัดทำขึ้นสำหรับ Google Cloud Platform ข้อผิดพลาดที่พบบ่อยขณะตรวจสอบการเดินทางมีดังนี้

HTTP RPC คำอธิบาย
400 INVALID_ARGUMENT ลูกค้าระบุชื่อการเดินทางไม่ถูกต้อง ชื่อการเดินทางต้องอยู่ในรูปแบบ providers/{provider_id}/trips/{trip_id} provider_id ต้องเป็นรหัสของโปรเจ็กต์ที่อยู่ในระบบคลาวด์ของผู้ให้บริการ
401 ไม่ได้ตรวจสอบสิทธิ์ คำขอไม่ได้รับการตรวจสอบสิทธิ์เนื่องจากโทเค็น JWT ไม่ถูกต้อง ข้อผิดพลาดนี้จะเกิดขึ้นหากมีการเซ็นโทเค็น JWT โดยไม่มีรหัสทริปหรือโทเค็น JWT หมดอายุ
403 PERMISSION_DENIED ไคลเอ็นต์ไม่มีสิทธิ์เพียงพอ ข้อผิดพลาดนี้จะเกิดขึ้นหากโทเค็น JWT ไม่ถูกต้อง ไคลเอ็นต์ไม่มีสิทธิ์ หรือไม่ได้เปิดใช้ API สำหรับโปรเจ็กต์ไคลเอ็นต์ โทเค็น JWT อาจขาดหายไปหรือมีการลงชื่อด้วยรหัสการเดินทางที่ไม่ตรงกับรหัสการเดินทางที่ขอ
429 RESOURCE_EXHAUSTED โควต้าทรัพยากรเป็น 0 หรืออัตราการรับส่งข้อมูลเกินขีดจำกัด
503 UNAVAILABLE ไม่พร้อมให้บริการ โดยทั่วไปเซิร์ฟเวอร์จะล่ม
504 DEADLINE_EXCEEDED เกินกำหนดเวลาในการส่งคำขอแล้ว กรณีนี้จะเกิดขึ้นก็ต่อเมื่อผู้โทรมีกำหนดเวลา ที่น้อยกว่ากำหนดเวลาเริ่มต้นของเมธอด (เช่น กำหนดเวลาที่ขอมาไม่เพียงพอให้เซิร์ฟเวอร์ประมวลผลคำขอ) และคำขอไม่เสร็จสิ้นภายในกำหนดเวลา

ดูข้อมูลเพิ่มเติมได้ที่ การจัดการข้อผิดพลาดเกี่ยวกับ SDK ของผู้บริโภค