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

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

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

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

อุปกรณ์เคลื่อนที่ต้องใช้ 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 Console ใหม่หรือเลือกโปรเจ็กต์ที่มีอยู่เพื่อใช้กับ Consumer SDK รอสักครู่จนกว่าโปรเจ็กต์ใหม่จะปรากฏใน Google Cloud Console

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

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

เพิ่ม SDK ของผู้บริโภคลงในแอปของคุณ

Consumer SDK พร้อมให้ใช้งานผ่านที่เก็บส่วนตัวของ Maven ที่เก็บจะรวมไฟล์ Project Object Model (.pom) และ Javadocs ของ SDK วิธีเพิ่ม 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 สำหรับเวอร์ชัน 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 ของผู้บริโภคจะขึ้นอยู่กับ 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 ดูข้อมูลเพิ่มเติมที่การตรวจสอบสิทธิ์และการให้สิทธิ์ของ Fleet Engine

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

Callback ของ JSON Web Token

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

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

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

ตัวแสดงผล Maps SDK และ Maps

SDK สำหรับผู้บริโภคเวอร์ชัน 2.x.x รองรับ Maps SDK สำหรับ Android เวอร์ชัน 18.1.0 ขึ้นไป ตารางด้านล่างจะสรุปตัวแสดงผลเริ่มต้นตามเวอร์ชัน Maps SDK และการรองรับของโหมดแสดงภาพทั้ง 2 แบบ เราขอแนะนำให้ใช้ตัวแสดงผลเวอร์ชันล่าสุด แต่หากต้องการใช้โหมดแสดงภาพเดิม คุณสามารถระบุอย่างชัดแจ้งโดยใช้ MapsInitializer.initialize()

เวอร์ชันของ Maps SDK รองรับโหมดแสดงภาพล่าสุด รองรับตัวแสดงผลแบบเดิม ตัวแสดงผลเริ่มต้น
เวอร์ชัน 18.1.0 และเวอร์ชันที่ต่ำกว่า ได้ ได้ เดิม*
V18.2.0 ได้ ได้ ล่าสุด

* การเปิดตัว Maps Renderer ใหม่จะใช้โหมดแสดงภาพล่าสุดเป็นค่าเริ่มต้น

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

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>

เริ่มต้น Maps SDK ก่อนเริ่มต้น Consumer 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) และ Vector แบบถอนออกได้

หากการออกแบบแอปกำหนดให้รองรับอุปกรณ์ 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 แบบไม่พร้อมกันใน Callback จากนั้นใช้ 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() นอกเหนือจากพารามิเตอร์ Callback แล้ว จำเป็นต้องใช้กิจกรรมหรือ Fragment ที่มี และ 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 ใน 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 จะจับตำแหน่งกล้องไว้ที่ตำแหน่งของอุปกรณ์

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

Consumer SDK สำหรับโซลูชันในตัวของ Android: กล้องอัตโนมัติ

Consumer 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 การใช้แผนที่ผู้บริโภคช่วยให้แอปและบริการร่วมเดินทางของคุณโต้ตอบกับ GoogleMap เดียวกันได้อย่างราบรื่น ตัวอย่างเช่น GoogleMap อนุญาตให้ลงทะเบียน Callback เพียงครั้งเดียว แต่ ConsumerGoogleMap รองรับ Callback ที่ลงทะเบียนแบบคู่ Callback เหล่านี้อนุญาตให้แอปและการแชร์รถโดยสารสามารถลงทะเบียน Callback ซึ่งเราเรียกใช้ตามลำดับ

ConsumerController

ConsumerController มอบการเข้าถึงฟังก์ชันการทำงานของการแชร์การเดินทาง เช่น การตรวจสอบการเดินทาง การควบคุมสถานะการเดินทาง และการตั้งค่าตำแหน่ง

ตั้งค่าการแชร์เส้นทาง

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

  1. ลงทะเบียน Listener ในออบเจ็กต์ 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 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 ของผู้บริโภค