Pakiet SDK dla klientów indywidualnych na Androida

Za pomocą pakietu SDK dla klientów indywidualnych możesz utworzyć i uruchomić podstawową aplikację dla użytkowników indywidualnych zintegrowaną z usługami backendu rozwiązania w zakresie usług przejazdów na żądanie i dostarczania. Możesz utworzyć aplikację Podróż i Postęp przetwarzania zamówienia, która może wyświetlać aktywną podróż, odpowiadać na aktualizacje podróży i obsługiwać związane z nią błędy.

Pakiet Consumer SDK ma architekturę modułową, dlatego możesz używać części interfejsu API, których chcesz używać w konkretnej aplikacji, i integrować je z własnymi interfejsami API, usługami backendu udostępnianymi przez Fleet Engine i dodatkowymi interfejsami API Google Maps Platform.

Minimalne wymagania systemowe

Na urządzeniu mobilnym musi być zainstalowany Android 6.0 (poziom interfejsu API 23) lub nowszy.

Konfiguracja kompilacji i zależności

W repozytorium Google Maven jest dostępny pakiet SDK dla klientów indywidualnych w wersji 1.99.0 lub nowszej. Używany wcześniej kanał repozytorium prywatnego został wycofany.

Gradle

Dodaj do pliku build.gradle te informacje:

repositories {
    ...
    google()
}

Maven

Dodaj do pliku pom.xml te informacje:

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

Konfiguracja projektu

Aby można było używać pakietu SDK Consumer SDK na Androida, aplikacja musi być kierowana na system minSdkVersion w wersji 23 lub nowszej.

Aby uruchomić aplikację stworzoną przy użyciu pakietu SDK dla klientów indywidualnych, na urządzeniu z Androidem muszą być zainstalowane Usługi Google Play.

Konfigurowanie projektu programistycznego

Aby skonfigurować projekt programistyczny i uzyskać dla niego klucz interfejsu API w konsoli Google Cloud:

  1. Utwórz nowy projekt konsoli Google Cloud lub wybierz istniejący projekt do użycia z pakietem SDK dla klientów indywidualnych. Zaczekaj kilka minut, aż nowy projekt pojawi się w konsoli Google Cloud.

  2. Aby uruchomić aplikację w wersji demonstracyjnej, Twój projekt musi mieć dostęp do pakietu Maps SDK na Androida. W konsoli Google Cloud wybierz Interfejsy API i usługi > Biblioteka, a następnie wyszukaj i włącz Maps SDK na Androida.

  3. Aby uzyskać klucz interfejsu API dla projektu, kliknij Interfejsy API i usługi > Dane logowania > Utwórz dane logowania > Klucz interfejsu API. Jeśli chcesz dowiedzieć się, jak uzyskać klucz interfejsu API, przeczytaj, jak uzyskać klucz interfejsu API.

Dodaj do aplikacji pakiet SDK dla klientów indywidualnych

Pakiet SDK dla klientów indywidualnych jest dostępny w prywatnym repozytorium Maven. Repozytorium zawiera pliki modelu obiektu pakietu SDK (.pom) i dokumenty Javadocs. Aby dodać do aplikacji pakiet SDK dla konsumentów:

  1. Skonfiguruj środowisko, aby uzyskać dostęp do hosta Maven w sposób opisany w poprzedniej sekcji.

    Jeśli w settings.gradle masz zadeklarowaną scentralizowaną konfigurację zarządzania zależnościami, wyłącz ją w następujący sposób.

    • Usuń w settings.gradle ten blok kodu:

      import org.gradle.api.initialization.resolve.RepositoriesMode
      dependencyResolutionManagement {
          repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
          repositories {
              google()
              mavenCentral()
          }
      }
      
  2. Dodaj poniższą zależność do konfiguracji Gradle lub Maven, zastępując zmienną VERSION_NUMBER odpowiednią wersją pakietu Consumer SDK.

    Gradle

    Dodaj do build.gradle:

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

    Maven

    Dodaj do pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-consumer</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  3. Pakiet SDK dla klientów indywidualnych korzysta z pakietu Maps SDK. Zależność ta jest skonfigurowana w taki sposób, że jeśli wersja pakietu Maps SDK nie jest wyraźnie określona w pliku konfiguracji kompilacji (tak jak poniżej), to po opublikowaniu nowej wersji pakietu Maps SDK pakiet Consumer SDK będzie nadal korzystać z minimalnej wymaganej wersji pakietu Maps SDK.

    Gradle

    Dodaj do build.gradle:

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

    Maven

    Dodaj do pom.xml:

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

Dodawanie klucza interfejsu API do aplikacji

Po dodaniu do aplikacji pakietu Consumer SDK dodaj do niej klucz interfejsu API. Musisz użyć klucza interfejsu API projektu uzyskanego podczas konfigurowania projektu programistycznego.

W tej sekcji dowiesz się, jak przechowywać klucz interfejsu API, aby aplikacja mogła lepiej się do niego odwoływać. Nie należy sprawdzać klucza interfejsu API w systemie kontroli wersji. Powinien on być przechowywany w pliku local.properties, który znajduje się w katalogu głównym projektu. Więcej informacji o pliku local.properties znajdziesz w artykule o plikach właściwości Gradle.

Aby usprawnić to zadanie, możesz użyć wtyczki do Gradle obiektów tajnych dla Androida.

Aby zainstalować wtyczkę i zapisać klucz interfejsu API:

  1. Otwórz plik build.gradle poziomu głównego i dodaj poniższy kod do elementu dependencies w buildscript.

    Zakręcony

    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. Otwórz plik build.gradle na poziomie aplikacji i dodaj poniższy kod do elementu plugins.

    Zakręcony

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

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. Jeśli używasz Androida Studio, zsynchronizuj projekt z Gradle.

  4. Otwórz local.properties w katalogu na poziomie projektu, a następnie dodaj ten kod. Zastąp YOUR_API_KEY swoim kluczem interfejsu API.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. W pliku AndroidManifest.xml przejdź do miejsca com.google.android.geo.API_KEY i zaktualizuj atrybut android:value w ten sposób:

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

Ten przykład zawiera pełny plik manifestu przykładowej aplikacji:

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

Umieść w aplikacji wymagane informacje o źródłach

Jeśli w swojej aplikacji używasz pakietu SDK dla klientów indywidualnych, w sekcji Informacje prawne o aplikacji musisz umieścić tekst atrybucji i licencje open source. Informacje o źródłach najlepiej dodawać jako niezależną pozycję menu lub jako część pozycji Informacje.

Informacje o licencjach znajdziesz w pliku „third_party_licenses.txt” w przywróconym pliku AAR.

Informacje o tym, jak dołączać powiadomienia o oprogramowaniu open source, znajdziesz na https://developers.google.com/android/guides/opensource.

Uwierzytelnianie za pomocą pakietu SDK klienta

Pakiet SDK Consumer SDK umożliwia uwierzytelnianie za pomocą tokenów sieciowych JSON. Token internetowy JSON (JWT) to podstawowy token dostępu JSON, który udostępnia co najmniej 1 deklarację dotyczącą usługi. Serwer może na przykład wygenerować token z deklaracją „zalogował się jako administrator” i przekazać go klientowi. Za pomocą tego tokena klient może potwierdzić, że jest zalogowany jako administrator.

Pakiet SDK dla klientów indywidualnych używa do komunikacji z flotą silnika internetowego tokena internetowego JSON udostępnionego przez aplikację. Więcej informacji znajdziesz w artykule Uwierzytelnianie i autoryzacja Fleet Engine.

Token autoryzacji musi zawierać deklarację tripid:TRIP_ID w nagłówku authorization tokena, gdzie TRIP_ID to identyfikator podróży. Daje to pakietowi SDK klienta dostęp do szczegółów podróży, takich jak pozycja pojazdu, trasa i szacowany czas dotarcia.

Wywołania zwrotne tokena internetowego JSON

Pakiet SDK klienta rejestruje wywołanie zwrotne tokena autoryzacji w aplikacji podczas inicjowania. Pakiet SDK wywołuje aplikację, aby uzyskać token dla wszystkich żądań sieciowych, które wymagają autoryzacji.

Zdecydowanie zalecamy, aby tokeny autoryzacji pamięci podręcznej implementacji wywołania zwrotnego były odświeżane tylko po upływie czasu expiry. Tokeny powinny być wydawane z godzinną datą ważności.

Wywołanie zwrotne tokena autoryzacji określa, który token usługi jest wymagany przez usługę TripService. Zapewnia też wymagane tripId na potrzeby kontekstu.

Poniższy przykładowy kod pokazuje, jak wdrożyć wywołanie zwrotne tokena autoryzacji.

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

Inicjowanie interfejsu API

Przed wykonaniem tych procedur zakładamy, że masz włączone odpowiednie usługi i pakiet Consumer SDK.

Pobieranie instancji ConsumerApi

Aby można było korzystać z pakietu SDK Consumer SDK, aplikacja musi zainicjować ConsumerApi asynchronicznie. Interfejs API to jedyny system. Metoda inicjowania zajmuje AuthTokenFactory. Fabryka generuje w razie potrzeby nowe tokeny JWT dla użytkownika.

providerId to identyfikator projektu Google Cloud. Więcej informacji o tworzeniu projektu znajdziesz w przewodniku użytkownika Fleet Engine.

Aplikacja powinna implementować AuthTokenFactory w sposób opisany w artykule Uwierzytelnianie klienta za pomocą pakietu 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 i mechanizmy renderowania map

Pakiet Consumer SDK w wersji 2.x.x obsługuje pakiet Maps SDK na Androida w wersji 18.1.0 lub nowszej. W tabeli poniżej znajdziesz podsumowanie domyślnego mechanizmu renderowania według wersji pakietu SDK Map Google oraz informacje o obsłudze obu mechanizmów renderowania. Zalecamy korzystanie z najnowszego mechanizmu renderowania, jeśli jednak chcesz użyć starszej wersji mechanizmu renderowania, możesz ją jednoznacznie określić za pomocą metody MapsInitializer.initialize().

Wersja pakietu SDK Maps Obsługuje najnowszy mechanizm renderowania Obsługuje starszy mechanizm renderowania Domyślny mechanizm renderowania
Wersja 18.1.0 i starsze Tak Tak Starsza wersja*
V18.2.0 Tak Tak Najnowsze

* Po wdrożeniu nowego mechanizmu renderowania Map domyślnym ustawieniem będzie „Najnowsza wersja mechanizmu renderowania”.

Dodaj pakiet Maps SDK jako zależność

Gradle

Dodaj do build.gradle:

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

Maven

Dodaj do pom.xml:

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

Zainicjuj pakiet SDK Maps SDK przed zainicjowaniem pakietu dla klientów indywidualnych

W klasie Application lub startowej klasie Activity wywołaj MapsInitializer.initialize() i poczekaj na wynik żądania mechanizmu renderowania, zanim zainicjujesz pakiet SDK dla klientów indywidualnych.

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

Tworzenie interfejsu użytkownika

Interfejs swojej aplikacji możesz utworzyć za pomocą ConsumerMapFragment lub ConsumerMapView. ConsumerMapFragment pozwala zdefiniować mapę za pomocą Fragment, a ConsumerMapView pozwala używać View. Funkcje udostępniania przejazdów są takie same zarówno w usłudze ConsumerMapView, jak i w ConsumerMapFragment. Możesz wybrać taką opcję w zależności od tego, czy wersja View czy Fragment lepiej sprawdzi się w Twojej aplikacji.

Dodanie obsługi elementów rysowanych w interfejsie API 19 (KitKat) i wektorowych

Jeśli projekt Twojej aplikacji wymaga obsługi urządzeń z interfejsem API 19 (KitKat) i wektorowych obiektów rysowalnych, dodaj ten kod do swojej aktywności. Rozszerzenie AppCompatActivity umożliwia korzystanie z obiektów rysowania wektorów w pakiecie SDK dla klientów indywidualnych.

Java

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

// ...

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

Kotlin

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

// ...

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

Dodawanie fragmentu lub widoku mapy

Tworzysz mapę do wyświetlania udostępniania podróży we fragmencie Androida lub widoku zdefiniowanym w pliku XML układu aplikacji (w lokalizacji /res/layout). Fragment (lub widok) daje potem dostęp do mapy udostępniania trasy, do której aplikacja może uzyskiwać dostęp i ją modyfikować. Mapa zawiera też uchwyt do ConsumerController, który umożliwia aplikacji dostosowywanie i dostosowywanie sposobu udostępniania podróży.

Udostępnianie mapy i kontrolera

Mapę udostępniania trasy możesz zdefiniować jako fragment (za pomocą ConsumerMapFragment) lub widok (za pomocą ConsumerMapView), jak pokazano w tym przykładzie kodu. Metoda onCreate() powinna następnie wywołać metodę getConsumerGoogleMapAsync(callback), która zwraca w wywołaniu zwrotnym asynchronicznie wartość ConsumerGoogleMap. Następnie za pomocą ConsumerGoogleMap możesz wyświetlić informacje o trasie, które można zaktualizować w razie potrzeby aplikacji.

ConsumerMapFragment

Definiujesz ten fragment w pliku XML układu aplikacji, zgodnie z poniższym przykładem kodu.

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

Wywołanie getConsumerGoogleMapAsync() powinno pochodzić z metody 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

Widok można wykorzystać we fragmencie lub w aktywności, zgodnie z definicją w pliku 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" />

Wywołanie getConsumerGoogleMapAsync() powinno pochodzić z onCreate(). Oprócz parametru wywołania zwrotnego wymagany jest element zawierający aktywność lub fragment i zasadę GoogleMapOptions (która może być pusta), która zawiera atrybuty konfiguracji MapView. Klasa bazowa działania lub fragmentu musi być albo FragmentActivity albo obsługą Fragment, ponieważ zapewnia dostęp do cyklu życia.

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

Element MapView we fragmencie jest taki sam jak w przykładzie powyżej dla elementu MapView w aktywności. Jedyna różnica jest taka, że fragment rozszerza układ zawierający element MapView w metodzie fragmentu 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)
  }
}

Dostosowywanie powiększenia aparatu w celu skoncentrowania się na podróży

Domyślny przycisk Moja lokalizacja wbudowany w pakiet SDK Map Google kieruje aparat na lokalizację urządzenia.

Jeśli aktywna jest sesja udostępniania trasy, możesz ustawić aparat tak, aby koncentrować się na trasie, a nie na lokalizacji urządzenia.

Wbudowany pakiet SDK dla użytkowników urządzeń z Androidem: AutoCamera

Aby umożliwić Ci skupienie się na podróży, a nie na lokalizacji urządzenia, pakiet Consumer SDK udostępnia domyślnie włączoną funkcję AutoCamera Kamera robi zbliżenie, by skupić się na trasie współdzielonej podróży i następnym punkcie na trasie.

AutoCamera

Dostosowywanie działania kamery

Jeśli chcesz mieć większą kontrolę nad działaniem kamery, możesz wyłączyć lub włączyć automatyczną kamerę za pomocą funkcji ConsumerController.setAutoCameraEnabled().

ConsumerController.getCameraUpdate() zwraca w danym momencie zalecane wartości progowe kamery. Następnie możesz podać ten element CameraUpdate jako argument funkcji GoogleMap.moveCamera() lub GoogleMap.animateCamera().

Korzystaj ze wspólnych przejazdów i map

Aby obsługiwać wspólne przejazdy i interakcję z mapą w aplikacji, musisz mieć dostęp do ConsumerGoogleMap i ConsumerController. ConsumerMapFragment i ConsumerMapView asynchronicznie zwracają ConsumerGoogleMap w ConsumerMapReadyCallback. ConsumerGoogleMap zwraca ConsumerController od: getConsumerController(). Aby uzyskać dostęp do usług ConsumerGoogleMap i ConsumerController, wykonaj te czynności.

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 to klasa kodu dla klasy GoogleMap. Zapewnia aplikacji możliwość interakcji z mapą za pomocą interfejsu API odpowiednika GoogleMap. Dzięki mapie dla klientów aplikacja i wspólne przejazdy mogą płynnie współdziałać z tą samą bazą danych GoogleMap. Na przykład GoogleMap umożliwia rejestrację tylko z jednym wywołaniem zwrotnym, ale ConsumerGoogleMap obsługuje podwójne zarejestrowane wywołania zwrotne. Te wywołania zwrotne umożliwiają aplikacji i udostępnianiu przejazdów rejestrowanie wywołań zwrotnych, które są wywoływane sekwencyjnie.

ConsumerController

ConsumerController umożliwia dostęp do funkcji wspólnych przejazdów, np. monitorowania przejazdów, kontrolowania ich stanu i ustawiania lokalizacji.

Konfigurowanie udostępniania podróży

Gdy backend dopasuje klienta do pojazdu, użyj funkcji JourneySharingSession, aby rozpocząć interfejs udostępniania ścieżki. Udostępnianie trasy pokazuje dopasowaną lokalizację pojazdu i trasę. Po zaimplementowaniu pakietu SDK w aplikacji możesz dodać funkcję monitorowania podróży, nasłuchiwania aktualizacji i obsługi błędów. W poniższych procedurach przyjęto, że usługi backendu są dostępne i że usługi dopasowywania konsumentów do pojazdów działają.

  1. Zarejestruj nasłuch w obiekcie TripModel, aby uzyskać szczegółowe informacje o podróży, takie jak szacowany czas przyjazdu (szacowany czas przyjazdu) i przebyta odległość, jaką musi przebyć pojazd przed przyjazdem.

    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. Skonfiguruj podróż w aplikacji 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)
    

Przestań udostępniać trasę

Pamiętaj, aby zatrzymać udostępnianie ścieżek, gdy nie jest już potrzebne, na przykład w przypadku zniszczenia aktywności hosta. Zatrzymanie udostępniania ścieżek powoduje też zatrzymanie żądań sieciowych wysyłanych do Fleet Engine i zapobiega wyciekom pamięci.

Ten przykładowy kod pokazuje, jak zatrzymać udostępnianie przebiegu.

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

Obsługa błędów związanych z podróżą

Metoda onTripRefreshError wyświetla błędy, które występują podczas monitorowania podróży. Mapowanie błędów pakietu Consumer SDK jest zgodne z tymi samymi wytycznymi dotyczącymi protokołu HTTP/RPC, które są stosowane w przypadku Google Cloud Platform. Typowe błędy wykrywane podczas monitorowania podróży to między innymi:

HTTP RPC Opis
400 INVALID_ARGUMENT Klient podał nieprawidłową nazwę podróży. Nazwa podróży musi mieć format providers/{provider_id}/trips/{trip_id}. provider_id musi być identyfikatorem projektu Cloud należącego do dostawcy usług.
401 BEZ UWIERZYTELNIANIA Żądanie nie zostało uwierzytelnione z powodu nieprawidłowego tokena JWT. Ten błąd występuje, jeśli token JWT zostanie podpisany bez identyfikatora podróży lub token JWT wygasł.
403 PERMISSION_DENIED nie ma wystarczających uprawnień. Ten błąd występuje, jeśli token JWT jest nieprawidłowy, klient nie ma uprawnień lub interfejs API nie jest włączony w projekcie klienta. Być może brakuje tokena JWT lub token jest podpisany identyfikatorem podróży, który nie pasuje do żądanego identyfikatora podróży.
429 RESOURCE_EXHAUSTED Limit zasobów wynosi zero lub szybkość ruchu przekracza limit.
503 PRODUKT NIEDOSTĘPNY Usługa niedostępna Zwykle serwer jest niedostępny.
504 DEADLINE_EXCEEDED Przekroczono termin prośby. Dzieje się tak tylko wtedy, gdy osoba wywołująca ustawi termin krótszy niż domyślny termin w metodzie (tzn. żądany termin jest niewystarczający na przetworzenie żądania przez serwer), a żądanie nie zostało ukończone w wyznaczonym terminie.

Więcej informacji znajdziesz w artykule Obsługa błędów w pakietach SDK dla klientów indywidualnych.