Bắt đầu với SDK người tiêu dùng dành cho Android

Bạn có thể sử dụng SDK người tiêu dùng để tạo và chạy một ứng dụng cơ bản dành cho người tiêu dùng, được tích hợp với các dịch vụ phụ trợ Giải pháp gọi xe và giao hàng theo yêu cầu. Bạn có thể tạo ứng dụng Chuyến đi và Tiến trình đặt hàng có thể hiển thị chuyến đi đang hoạt động, phản hồi thông tin cập nhật về chuyến đi và xử lý các lỗi về chuyến đi.

Vì SDK người dùng có cấu trúc mô-đun, nên bạn có thể sử dụng các phần của API mà bạn muốn dùng cho ứng dụng cụ thể và tích hợp các phần đó với API riêng của bạn, các dịch vụ phụ trợ do Fleet Engine cung cấp và bổ sung API của Nền tảng Google Maps.

Yêu cầu tối thiểu về hệ thống

Thiết bị di động phải chạy Android 6.0 (API cấp 23) trở lên.

Cấu hình Maven

Người dùng SDK phiên bản 1.99.0 trở lên hiện có sẵn trong kho lưu trữ Maven của Google.

Gradle

Thêm đoạn mã sau vào tệp build.gradle của bạn:

repositories {
    ...
    google()
}

Maven

Thêm đoạn mã sau vào tệp pom.xml của bạn:

<project>
  ...
  <repositories>
    <repository>
      <id>google-maven-repository</id>
      <url>https://maven.google.com</url>
    </repository>
  </repositories>
  ...
</project>

Cấu hình dự án

Để sử dụng SDK người tiêu dùng cho Android, ứng dụng của bạn phải nhắm đến minSdkVersion 23 trở lên.

Để chạy một ứng dụng được tạo bằng SDK người tiêu dùng, thiết bị Android phải cài đặt Dịch vụ Google Play.

Thiết lập dự án phát triển

Cách thiết lập dự án phát triển và lấy khoá API cho dự án trên Google Cloud Console:

  1. Tạo dự án Google Cloud Console mới hoặc chọn dự án hiện có để sử dụng với SDK người dùng. Đợi vài phút cho đến khi dự án mới xuất hiện trên Google Cloud Console.

  2. Để chạy ứng dụng minh hoạ, dự án của bạn phải có quyền truy cập vào SDK Maps dành cho Android. Trong Google Cloud Console, hãy chọn APIs & Services > Library (API và dịch vụ > Thư viện), sau đó tìm kiếm và bật SDK Maps cho Android.

  3. Lấy khoá API cho dự án bằng cách chọn APIs & Services > Credentials > Create credentials > API key (API và Dịch vụ > Thông tin xác thực > Tạo thông tin xác thực > Khoá API). Để biết thêm thông tin về cách lấy khoá API, hãy xem bài viết Lấy khoá API.

Thêm Consumer SDK vào ứng dụng

SDK Người dùng được cung cấp qua một kho lưu trữ Maven riêng tư. Kho lưu trữ bao gồm các tệp Mô hình đối tượng dự án (.pom) của SDK và tài liệu Java. Cách thêm Consumer SDK vào ứng dụng:

  1. Thiết lập môi trường để truy cập vào kho lưu trữ Maven của máy chủ như mô tả trong phần trước.

    Nếu bạn đã khai báo cấu hình quản lý phần phụ thuộc tập trung trong settings.gradle, hãy vô hiệu hoá cấu hình đó như sau.

    • Xoá khối mã dưới đây trong settings.gradle:

      import org.gradle.api.initialization.resolve.RepositoriesMode
      dependencyResolutionManagement {
          repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
          repositories {
              google()
              mavenCentral()
          }
      }
      
  2. Thêm phần phụ thuộc sau vào cấu hình Gradle hoặc Maven, thay thế phần giữ chỗ VERSION_NUMBER cho phiên bản SDK người dùng mong muốn.

    Gradle

    Thêm nội dung sau vào build.gradle của bạn:

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

    Maven

    Thêm nội dung sau vào pom.xml của bạn:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-consumer</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    

Thêm khoá API vào ứng dụng

Sau khi thêm SDK người dùng vào ứng dụng, hãy thêm khoá API vào ứng dụng. Bạn phải sử dụng khoá API dự án đã nhận được khi thiết lập dự án phát triển.

Phần này mô tả cách lưu trữ khoá API để ứng dụng của bạn có thể tham chiếu khoá đó một cách an toàn hơn. Bạn không nên kiểm tra khoá API trong hệ thống quản lý phiên bản của mình. Tệp này phải được lưu trữ trong tệp local.properties, nằm trong thư mục gốc của dự án. Để biết thêm thông tin về tệp local.properties, hãy xem các tệp thuộc tính Gradle.

Để đơn giản hoá tác vụ này, bạn có thể dùng Trình bổ trợ Bí mật cho Gradle cho Android.

Cách cài đặt trình bổ trợ và lưu trữ khoá API:

  1. Mở tệp build.gradle ở cấp độ gốc rồi thêm mã sau vào phần tử dependencies trong buildscript.

    Groovy

    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. Mở tệp build.gradle ở cấp ứng dụng rồi thêm mã sau vào phần tử plugins.

    Groovy

    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
    

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. Nếu bạn sử dụng Android Studio, hãy đồng bộ hoá dự án với Gradle.

  4. Mở local.properties trong thư mục cấp dự án, sau đó thêm mã sau. Thay thế YOUR_API_KEY bằng khoá API.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. Trong tệp AndroidManifest.xml, hãy chuyển đến com.google.android.geo.API_KEY rồi cập nhật thuộc tính android:value như sau:

    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="${MAPS_API_KEY}" />
    

Ví dụ sau đây minh hoạ một tệp kê khai đầy đủ cho một ứng dụng mẫu:

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

Bao gồm các thuộc tính bắt buộc trong ứng dụng của bạn

Nếu sử dụng SDK Người tiêu dùng trong ứng dụng, bạn phải đưa văn bản phân bổ và giấy phép nguồn mở vào mục thông báo pháp lý của ứng dụng. Bạn nên đưa các thuộc tính vào dưới dạng mục trình đơn độc lập hoặc dưới dạng mục trong trình đơn About (Giới thiệu).

Bạn có thể tìm thấy thông tin về giấy phép tại tệp "third_party_ permissions.txt" trong tệp AAR đã huỷ lưu trữ.

Hãy tham khảo https://developers.google.com/android/guides/opensource để biết cách đưa thông báo nguồn mở vào.

Xác thực SDK người dùng

SDK người dùng cung cấp phương thức xác thực bằng mã thông báo web JSON. Mã thông báo web JSON (JWT) là mã truy cập cơ sở JSON cung cấp một hoặc nhiều thông báo xác nhận quyền sở hữu đối với một dịch vụ. Ví dụ: máy chủ có thể tạo một mã thông báo với yêu cầu "đăng nhập với tư cách quản trị viên" và cung cấp mã đó cho ứng dụng. Sau đó, ứng dụng có thể sử dụng mã thông báo đó để chứng minh rằng họ đã đăng nhập với tư cách quản trị viên.

SDK người dùng sử dụng Mã thông báo web JSON do ứng dụng cung cấp để giao tiếp với Fleet Engine. Xem bài viết Xác thực và uỷ quyền cho nhóm thiết bị để biết thêm thông tin.

Mã thông báo uỷ quyền phải bao gồm thông báo xác nhận quyền sở hữu tripid:TRIP_ID trong tiêu đề authorization của mã thông báo, trong đó TRIP_ID là mã chuyến đi. Nhờ vậy, SDK người tiêu dùng có thể truy cập thông tin chi tiết về chuyến đi, bao gồm cả vị trí xe, tuyến đường và giờ đến dự kiến.

Lệnh gọi lại Mã thông báo web JSON

SDK người dùng sẽ đăng ký lệnh gọi lại mã thông báo uỷ quyền với ứng dụng trong quá trình khởi chạy. SDK gọi ứng dụng để lấy mã thông báo cho tất cả các yêu cầu mạng yêu cầu uỷ quyền.

Bạn nên chỉ nên làm mới các mã thông báo uỷ quyền trong bộ nhớ đệm khi triển khai lệnh gọi lại và chỉ làm mới các mã này khi thời gian expiry đã trôi qua. Mã thông báo phải được phát hành với thời hạn là một giờ.

Lệnh gọi lại mã thông báo uỷ quyền chỉ định mã thông báo dịch vụ nào cần thiết cho dịch vụ TripService. Mã này cũng cung cấp tripId cần thiết cho ngữ cảnh.

Ví dụ về mã sau đây minh hoạ cách triển khai lệnh gọi lại mã thông báo uỷ quyền.

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

Khởi chạy API

Trước khi làm theo các quy trình này, hệ thống giả định rằng bạn đã bật các dịch vụ thích hợp và SDK người dùng.

Tải thực thể ConsumerApi

Để sử dụng SDK người dùng, ứng dụng của bạn cần khởi chạy ConsumerApi không đồng bộ. API này là một singleton. Phương thức khởi chạy sẽ lấy một AuthTokenFactory. Nhà máy sẽ tạo mã thông báo JWT mới cho người dùng khi cần.

providerIdMã dự án cho dự án của bạn trên Google Cloud. Vui lòng xem Hướng dẫn sử dụng Fleet Engine để biết thêm thông tin về cách tạo dự án.

Ứng dụng của bạn nên triển khai AuthTokenFactory như mô tả trong phần Xác thực SDK người tiêu dùng.

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
}

Khởi động SDK Maps để yêu cầu trình kết xuất ưu tiên

Người dùng SDK phiên bản 2.0.0 hỗ trợ SDK Bản đồ cho Android phiên bản 18.1.0 trở lên. Công cụ này hỗ trợ các yêu cầu chỉ định trình kết xuất đồ hoạ Google Maps ưu tiên. Để biết thông tin chi tiết, hãy tham khảo bài viết Trình kết xuất bản đồ mới(chọn sử dụng).

Thêm SDK Maps làm phần phụ thuộc

Gradle

Thêm nội dung sau vào build.gradle của bạn:

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

Maven

Thêm nội dung sau vào pom.xml của bạn:

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

Khởi chạy SDK bản đồ trước khi khởi chạy SDK người dùng

Trong lớp Application hoặc khởi động Activity, hãy gọi MapsInitializer.initialize() và đợi kết quả yêu cầu kết xuất trước khi khởi chạy SDK Người tiêu dùng.

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

Tạo giao diện người dùng

Bạn có thể sử dụng ConsumerMapFragment hoặc ConsumerMapView để tạo giao diện người dùng cho ứng dụng của mình. ConsumerMapFragment cho phép bạn xác định bản đồ bằng Fragment, còn ConsumerMapView cho phép bạn sử dụng View. Chức năng chia sẻ chuyến đi giống nhau ở cả ConsumerMapViewConsumerMapFragment, vì vậy, bạn có thể chọn một chế độ dựa trên việc View hay Fragment phù hợp hơn với ứng dụng của mình.

Thêm tính năng hỗ trợ cho API 19 (KitKat) và các vectơ vẽ được

Nếu thiết kế ứng dụng của bạn yêu cầu hỗ trợ các thiết bị API 19 (KitKat) và các vectơ vẽ được, hãy thêm mã sau vào Hoạt động của bạn. Mã này mở rộng AppCompatActivity để sử dụng các vectơ vẽ được trong SDK người dùng.

Java

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

// ...

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

Kotlin

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

// ...

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

Thêm mảnh hoặc chế độ xem bản đồ

Bạn tạo bản đồ để hiển thị thông tin chia sẻ hành trình trong một mảnh Android hoặc thành phần hiển thị mà bạn xác định trong tệp XML bố cục ứng dụng (nằm trong /res/layout). Sau đó, mảnh (hoặc chế độ xem) cung cấp quyền truy cập vào bản đồ chia sẻ hành trình mà ứng dụng của bạn có thể truy cập và sửa đổi. Bản đồ cũng cung cấp một đối tượng xử lý cho ConsumerController, cho phép ứng dụng của bạn kiểm soát và tuỳ chỉnh trải nghiệm chia sẻ hành trình.

Bản đồ và tay điều khiển chế độ chia sẻ hành trình

Bạn xác định bản đồ chia sẻ hành trình dưới dạng một mảnh (sử dụng ConsumerMapFragment) hoặc dưới dạng khung hiển thị (sử dụng ConsumerMapView), như trong đoạn mã ví dụ sau đây. Khi đó, phương thức onCreate() của bạn sẽ gọi getConsumerGoogleMapAsync(callback). Phương thức này sẽ trả về ConsumerGoogleMap không đồng bộ trong lệnh gọi lại. Sau đó, bạn sử dụng ConsumerGoogleMap để cho thấy hành trình chia sẻ và ứng dụng của bạn có thể cập nhật thông tin này nếu cần.

ConsumerMapFragment

Bạn xác định mảnh trong tệp XML bố cục ứng dụng, như được minh hoạ trong mã ví dụ sau đây.

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

Lệnh gọi đến getConsumerGoogleMapAsync() phải đến từ phương thức 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

Bạn có thể sử dụng thành phần hiển thị này trong một mảnh hoặc trong một hoạt động, như xác định trong tệp 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" />

Lệnh gọi đến getConsumerGoogleMapAsync() phải từ onCreate(). Ngoài tham số gọi lại, tham số này còn yêu cầu hoạt động hoặc mảnh có chứa hoạt động và GoogleMapOptions (có thể mang giá trị rỗng) chứa các thuộc tính cấu hình cho MapView. Lớp cơ sở hoạt động hoặc mảnh phải là FragmentActivity hoặc Fragment hỗ trợ (tương ứng), vì lớp này cung cấp quyền truy cập vào vòng đời của lớp đó.

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 trong một mảnh cũng giống như ví dụ trên đối với MapView trong một hoạt động, ngoại trừ việc mảnh tăng cường bố cục chứa MapView trong phương thức của mảnh 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)
  }
}

Điều chỉnh mức thu phóng của máy ảnh để lấy nét trong hành trình

Nút Vị trí của tôi mặc định được tích hợp trong SDK Maps đặt máy ảnh vào vị trí thiết bị.

Nếu có một phiên Chia sẻ hành trình đang hoạt động, bạn nên căn giữa camera để tập trung vào hành trình thay vì vị trí của thiết bị.

Giải pháp tích hợp sẵn SDK người dùng cho Android: AutoCamera

Để cho phép bạn tập trung vào hành trình thay vì vị trí thiết bị, SDK người dùng sẽ cung cấp tính năng AutoCamera được bật theo mặc định. Máy ảnh sẽ thu phóng để tập trung vào tuyến đường chia sẻ hành trình và điểm tham chiếu chuyến đi tiếp theo.

AutoCamera

Tuỳ chỉnh hoạt động của máy ảnh

Nếu cần kiểm soát hoạt động của máy ảnh nhiều hơn, bạn có thể tắt hoặc bật tính năng tự động camera bằng cách sử dụng ConsumerController.setAutoCameraEnabled().

ConsumerController.getCameraUpdate() trả về các giới hạn được đề xuất cho máy ảnh tại thời điểm đó. Sau đó, bạn có thể cung cấp CameraUpdate này làm đối số cho GoogleMap.moveCamera() hoặc GoogleMap.animateCamera().

Sử dụng tính năng đi chung xe và bản đồ

Để hỗ trợ hoạt động tương tác trên bản đồ và đi chung xe trong ứng dụng, bạn cần có quyền truy cập vào ConsumerGoogleMapConsumerController. ConsumerMapFragmentConsumerMapView đều trả về không đồng bộ ConsumerGoogleMap trong ConsumerMapReadyCallback. ConsumerGoogleMap trả về ConsumerController từ getConsumerController(). Bạn có thể truy cập ConsumerGoogleMapConsumerController như sau.

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 là một lớp trình bao bọc cho lớp GoogleMap. Công cụ này cho phép ứng dụng của bạn tương tác với bản đồ bằng một API tương đương với GoogleMap. Việc sử dụng bản đồ người tiêu dùng cho phép ứng dụng và dịch vụ đi chung xe của bạn tương tác liền mạch với cùng một GoogleMap cơ bản. Ví dụ: GoogleMap chỉ cho phép đăng ký một lệnh gọi lại duy nhất, nhưng ConsumerGoogleMap hỗ trợ các lệnh gọi lại được đăng ký kép. Các lệnh gọi lại này cho phép ứng dụng và dịch vụ đi chung xe đăng ký các lệnh gọi lại được gọi tuần tự.

ConsumerController

ConsumerController cung cấp quyền truy cập vào chức năng đi chung xe như theo dõi chuyến đi, kiểm soát trạng thái chuyến đi và đặt vị trí.

Thiết lập tính năng chia sẻ hành trình

Sau khi phần phụ trợ đã so khớp người tiêu dùng với một chiếc xe, hãy sử dụng JourneySharingSession để bắt đầu giao diện người dùng của tính năng chia sẻ hành trình. Tính năng chia sẻ hành trình cho thấy vị trí và tuyến đường của xe trùng khớp. Sau khi triển khai SDK trong ứng dụng, bạn có thể thêm chức năng theo dõi các chuyến đi, theo dõi thông tin cập nhật và xử lý lỗi. Các quy trình sau đây giả định rằng các dịch vụ phụ trợ đã có sẵn và các dịch vụ so khớp người tiêu dùng với xe đang hoạt động.

  1. Đăng ký trình nghe trên đối tượng TripModel để nhận thông tin chi tiết về chuyến đi, chẳng hạn như ETA (Thời gian đến ước tính) và quãng đường mà xe cần đi trước khi đến.

    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. Thiết lập chuyến đi của bạn bằng 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)
    

Dừng chia sẻ hành trình

Đảm bảo rằng bạn ngừng chia sẻ hành trình khi không còn cần đến, chẳng hạn như khi hoạt động lưu trữ bị huỷ bỏ. Việc dừng chia sẻ hành trình cũng sẽ dừng các yêu cầu về mạng gửi tới Fleet Engine và ngăn chặn việc rò rỉ bộ nhớ.

Mã mẫu sau đây minh hoạ cách dừng chia sẻ hành trình.

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

Xử lý lỗi chuyến đi

Phương thức onTripRefreshError hiển thị các lỗi xảy ra trong quá trình giám sát chuyến đi. Việc ánh xạ lỗi SDK người tiêu dùng tuân theo cùng các nguyên tắc HTTP/RPC được thiết lập cho Google Cloud Platform. Sau đây là các lỗi thường gặp trong quá trình giám sát chuyến đi:

HTTP RPC Nội dung mô tả
400 INVALID_ARGUMENT Khách hàng đã chỉ định tên chuyến đi không hợp lệ. Tên chuyến đi phải theo định dạng providers/{provider_id}/trips/{trip_id}. provider_id phải là mã nhận dạng của dự án trên đám mây do nhà cung cấp dịch vụ sở hữu.
401 KHÔNG XÁC THỰC Yêu cầu chưa được xác thực do mã thông báo JWT không hợp lệ. Lỗi này sẽ xảy ra nếu mã thông báo JWT được ký mà không có mã chuyến đi hoặc mã thông báo JWT đã hết hạn.
403 PERMISSION_DENIED Ứng dụng khách không có đủ quyền. Lỗi này xảy ra nếu mã thông báo JWT không hợp lệ, ứng dụng không có quyền hoặc API không được bật cho dự án ứng dụng. Có thể mã thông báo JWT bị thiếu hoặc mã thông báo được ký bằng một mã chuyến đi không khớp với mã chuyến đi đã yêu cầu.
429 RESOURCE_EXHAUSTED Hạn mức tài nguyên bằng 0 hoặc tỷ lệ lưu lượng truy cập vượt quá giới hạn.
503 UNAVAILABLE Dịch vụ hiện không hoạt động. Thông thường, máy chủ ngừng hoạt động.
504 DEADLINE_EXCEEDED Đã quá thời hạn yêu cầu. Điều này sẽ chỉ xảy ra nếu phương thức gọi đặt ra một thời hạn ngắn hơn thời hạn mặc định của phương thức (tức là thời hạn được yêu cầu không đủ để máy chủ xử lý yêu cầu) và yêu cầu không hoàn tất trong thời hạn đó.

Để biết thêm thông tin, hãy xem bài viết Xử lý lỗi SDK người tiêu dùng.