Migracja do nowego klienta pakietu SDK Miejsc

W tym przewodniku opisujemy zmiany między biblioteką zgodności Miejsc a nową, samodzielną wersją pakietu SDK Miejsc na Androida. Jeśli zamiast przechodzenia na nową, samodzielną wersję pakietu Places SDK dla Androida korzystasz z biblioteki zgodności Miejsc, z tego przewodnika dowiesz się, jak zaktualizować projekty, aby używać nowej wersji pakietu Places SDK dla Androida.

Jedynym sposobem na uzyskanie dostępu do funkcji i poprawek błędów w pakiecie Places SDK dla Androida w wersji nowszej niż 2.6.0 będzie skorzystanie z pakietu Places SDK dla Androida. Google zaleca jak najszybsze zaktualizowanie biblioteki zgodności do nowej wersji pakietu Places SDK na Androida.

Co się zmieniło?

Oto główne obszary zmian:

  • Nowa wersja pakietu Places SDK dla Androida jest rozpowszechniana jako statyczna biblioteka klienta. Przed styczniem 2019 r. pakiet SDK Miejsc na Androida był dostępny w Usługach Google Play. Od tego czasu udostępniliśmy bibliotekę zgodności Miejsc, aby ułatwić przejście na nowy pakiet SDK Miejsc na Androida.
  • Dostępne są zupełnie nowe metody.
  • Maski pól są teraz obsługiwane w przypadku metod, które zwracają szczegóły miejsc. Za pomocą masek pól możesz określić typy zwracanych danych o miejscach.
  • Ulepszyliśmy kody stanu używane do zgłaszania błędów.
  • Autouzupełnianie obsługuje teraz tokeny sesji.
  • Selektor miejsc nie jest już dostępny.

Informacje o bibliotece zgodności Miejsc

W styczniu 2019 r., po opublikowaniu wersji 1.0 samodzielnego pakietu SDK Miejsc na Androida na Androida, firma Google udostępniła bibliotekę zgodności, aby pomóc w migracji z wycofanej wersji pakietu Places SDK na Androida (com.google.android.gms:play-services-places) Usług Google Play.

Ta biblioteka zgodności została tymczasowo udostępniona do przekierowywania i tłumaczenia wywołań interfejsu API kierowanych na nową, samodzielną wersję Usług Google Play do momentu, w którym deweloperzy mogli przeprowadzić migrację swojego kodu, aby używać nowych nazw w samodzielnym pakiecie SDK. Dla każdej wersji pakietu Places SDK dla Androida, która została wydana od wersji od 1.0 do 2.6.0, opublikowano odpowiednią wersję biblioteki zgodności Miejsc, aby zapewnić równoważne funkcje.

Blokowanie i wycofywanie biblioteki zgodności Miejsc

Wszystkie wersje biblioteki zgodności pakietu SDK Miejsc na Androida zostały wycofane 31 marca 2022 r. Wersja 2.6.0 to ostatnia wersja biblioteki zgodności Miejsca. Jedynym sposobem na uzyskanie dostępu do funkcji i poprawek błędów w pakiecie Miejsca SDK na Androida w wersji nowszej niż 2.6.0 jest skorzystanie z pakietu Places SDK dla Androida.

Google zaleca przejście na pakiet SDK Miejsc na Androida, który zapewnia dostęp do nowych funkcji i krytycznych poprawek błędów występujących w wersjach nowszych niż 2.6.0. Jeśli obecnie używasz biblioteki zgodności, wykonaj czynności opisane poniżej w sekcji Instalowanie pakietu Places SDK na Androida, aby przeprowadzić migrację do pakietu Places SDK na Androida.

Instalowanie biblioteki klienta

Nowa wersja pakietu Places SDK dla Androida jest rozpowszechniana jako statyczna biblioteka klienta.

Użyj narzędzia Maven, aby dodać do projektu Android Studio pakiet SDK Miejsc na Androida:

  1. Jeśli korzystasz obecnie z biblioteki zgodności Miejsc:

    1. Zastąp następujący wiersz w sekcji dependencies:

          implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'

      Ten wiersz służy do przejścia na pakiet SDK Miejsc na Androida:

          implementation 'com.google.android.libraries.places:places:3.3.0'

  2. Jeśli używasz obecnie pakietu SDK Miejsc na Androida w wersji na potrzeby Usług Google Play:

    1. Zastąp następujący wiersz w sekcji dependencies:

          implementation 'com.google.android.gms:play-services-places:X.Y.Z'

      Ten wiersz służy do przejścia na pakiet SDK Miejsc na Androida:

          implementation 'com.google.android.libraries.places:places:3.3.0'

  3. Zsynchronizuj projekt Gradle.

  4. Ustaw minSdkVersion w projekcie aplikacji na 16 lub wyższą.

  5. Zaktualizuj zasoby „Technologia Google”:

    @drawable/powered_by_google_light // OLD
    @drawable/places_powered_by_google_light // NEW
    @drawable/powered_by_google_dark // OLD
    @drawable/places_powered_by_google_dark // NEW
    
  6. Utwórz aplikację. Jeśli zauważysz błędy kompilacji związane z konwersją na pakiet SDK Miejsc na Androida, zapoznaj się z informacjami w sekcjach poniżej, by dowiedzieć się, jak naprawić te błędy.

Zainicjuj nowego klienta pakietu Places SDK

Zainicjuj nowego klienta pakietu Places SDK w sposób podany w tym przykładzie:

// Add an import statement for the client library.
import com.google.android.libraries.places.api.Places;

...

// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);

// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);

Kody stanu

Zmienił się kod stanu błędów limitu zapytań na sekundę. Błędy limitu zapytań na sekundę są teraz zwracane przez PlaceStatusCodes.OVER_QUERY_LIMIT. Nie ma więcej limitów QPD.

Dodano te kody stanu:

  • REQUEST_DENIED – prośba została odrzucona. Możliwe przyczyny:

    • Nie podano klucza interfejsu API.
    • Podano nieprawidłowy klucz interfejsu API.
    • Interfejs Places API nie został włączony w konsoli Cloud.
    • Klucz interfejsu API został podany z nieprawidłowymi ograniczeniami.
  • INVALID_REQUEST – żądanie jest nieprawidłowe z powodu brakującego lub nieprawidłowego argumentu.

  • NOT_FOUND – nie znaleziono wyniku dla danego żądania.

Nowe metody

Nowa wersja pakietu Places SDK dla Androida wprowadza zupełnie nowe metody, które zostały zaprojektowane z myślą o spójności. Wszystkie nowe metody są zgodne z tymi zasadami:

  • W punktach końcowych nie używa się już czasownika get.
  • Obiekty żądań i odpowiedzi mają taką samą nazwę jak odpowiednia metoda klienta.
  • Obiekty żądań mają teraz monterów. Wymagane parametry są przekazywane jako parametry kreatora żądań.
  • Bufory nie są już używane.

W tej sekcji zaprezentujemy nowe metody i pokazujemy, jak działają.

Pobierz miejsce według identyfikatora

Użyj narzędzia fetchPlace(), aby uzyskać informacje o konkretnym miejscu. fetchPlace() działa podobnie do getPlaceById().

Aby pobrać miejsce, wykonaj te czynności:

  1. Wywołaj fetchPlace(), przekazując obiekt FetchPlaceRequest z identyfikatorem miejsca i listą pól określających dane miejsca do zwrócenia.

    // Define a Place ID.
    String placeId = "INSERT_PLACE_ID_HERE";
    
    // Specify the fields to return.
    List<Place.Field> placeFields = Arrays.asList(Place.Field.ID, Place.Field.NAME);
    
    // Construct a request object, passing the place ID and fields array.
    FetchPlaceRequest request = FetchPlaceRequest.builder(placeId, placeFields)
            .build();
    
    
  2. Wywołaj addOnSuccessListener(), aby obsłużyć FetchPlaceResponse. Zwracany jest pojedynczy wynik Place.

    // Add a listener to handle the response.
    placesClient.fetchPlace(request).addOnSuccessListener((response) -> {
      Place place = response.getPlace();
      Log.i(TAG, "Place found: " + place.getName());
    }).addOnFailureListener((exception) -> {
        if (exception instanceof ApiException) {
            ApiException apiException = (ApiException) exception;
            int statusCode = apiException.getStatusCode();
            // Handle error with given status code.
            Log.e(TAG, "Place not found: " + exception.getMessage());
        }
    });
    

Pobierz zdjęcie miejsca

Użyj opcji fetchPhoto(), aby zrobić zdjęcie miejsca. fetchPhoto() zwraca zdjęcia miejsca. Uprościliśmy wzór prośby o zdjęcie. Możesz teraz wysłać żądanie PhotoMetadata bezpośrednio z obiektu Place. Oddzielne żądanie nie jest już potrzebne. Maksymalna szerokość lub wysokość zdjęcia to 1600 pikseli. fetchPhoto() działa podobnie do getPhoto().

Aby pobrać zdjęcia miejsca, wykonaj te czynności:

  1. Skonfiguruj połączenie z: fetchPlace(). Pamiętaj, aby w prośbie uwzględnić pole PHOTO_METADATAS:

    List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
    
  2. Pobierz obiekt Place (w tym przykładzie użyto obiektu fetchPlace(), ale możesz też użyć findCurrentPlace()):

    FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
    
  3. Dodaj element OnSuccessListener, aby uzyskać metadane zdjęcia z wyniku Place w elemencie FetchPlaceResponse, a następnie użyj powstałych metadanych, aby uzyskać bitmapę i tekst źródła:

    placesClient.fetchPlace(placeRequest).addOnSuccessListener((response) -> {
        Place place = response.getPlace();
    
        // Get the photo metadata.
        PhotoMetadata photoMetadata = place.getPhotoMetadatas().get(0);
    
        // Get the attribution text.
        String attributions = photoMetadata.getAttributions();
    
        // Create a FetchPhotoRequest.
        FetchPhotoRequest photoRequest = FetchPhotoRequest.builder(photoMetadata)
                .setMaxWidth(500) // Optional.
                .setMaxHeight(300) // Optional.
                .build();
        placesClient.fetchPhoto(photoRequest).addOnSuccessListener((fetchPhotoResponse) -> {
            Bitmap bitmap = fetchPhotoResponse.getBitmap();
            imageView.setImageBitmap(bitmap);
        }).addOnFailureListener((exception) -> {
            if (exception instanceof ApiException) {
                ApiException apiException = (ApiException) exception;
                int statusCode = apiException.getStatusCode();
                // Handle error with given status code.
                Log.e(TAG, "Place not found: " + exception.getMessage());
            }
        });
    });
    

Znajdź miejsce z lokalizacji użytkownika

Użyj narzędzia findCurrentPlace(), aby znaleźć bieżącą lokalizację urządzenia użytkownika. findCurrentPlace() zwraca listę elementów typu PlaceLikelihood wskazujących, gdzie najprawdopodobniej będzie znajdować się urządzenie użytkownika. findCurrentPlace() działa podobnie do getCurrentPlace().

Aby poznać bieżącą lokalizację urządzenia użytkownika, wykonaj te czynności:

  1. Upewnij się, że aplikacja prosi o uprawnienia ACCESS_FINE_LOCATION i ACCESS_WIFI_STATE. Użytkownik musi przyznać uprawnienia dostępu do bieżącej lokalizacji swojego urządzenia. Więcej informacji znajdziesz w sekcji Wysyłanie prośby o uprawnienia aplikacji.

  2. Utwórz obiekt FindCurrentPlaceRequest zawierający listę typów danych dotyczących miejsc do zwrócenia.

      // Use fields to define the data types to return.
      List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME);
    
      // Use the builder to create a FindCurrentPlaceRequest.
      FindCurrentPlaceRequest request =
              FindCurrentPlaceRequest.builder(placeFields).build();
    
  3. Wywołaj polecenie findCurrentPlace i obsługa odpowiedzi. Najpierw sprawdź, czy użytkownik przyznał uprawnienia do korzystania z lokalizacji urządzenia.

      // Call findCurrentPlace and handle the response (first check that the user has granted permission).
      if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
          placesClient.findCurrentPlace(request).addOnSuccessListener(((response) -> {
              for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
                  Log.i(TAG, String.format("Place '%s' has likelihood: %f",
                          placeLikelihood.getPlace().getName(),
                          placeLikelihood.getLikelihood()));
                  textView.append(String.format("Place '%s' has likelihood: %f\n",
                          placeLikelihood.getPlace().getName(),
                          placeLikelihood.getLikelihood()));
              }
          })).addOnFailureListener((exception) -> {
              if (exception instanceof ApiException) {
                  ApiException apiException = (ApiException) exception;
                  Log.e(TAG, "Place not found: " + apiException.getStatusCode());
              }
          });
      } else {
          // A local method to request required permissions;
          // See https://developer.android.com/training/permissions/requesting
          getLocationPermission();
      }
    

Znajdowanie podpowiedzi autouzupełniania

Używaj funkcji findAutocompletePredictions(), aby zwracać prognozy miejsc w odpowiedzi na zapytania użytkowników. findAutocompletePredictions() działa podobnie do getAutocompletePredictions().

Oto przykład wywoływania funkcji findAutocompletePredictions():

// Create a new token for the autocomplete session. Pass this to FindAutocompletePredictionsRequest,
// and once again when the user makes a selection (for example when calling fetchPlace()).
AutocompleteSessionToken token = AutocompleteSessionToken.newInstance();
// Create a RectangularBounds object.
RectangularBounds bounds = RectangularBounds.newInstance(
  new LatLng(-33.880490, 151.184363),
  new LatLng(-33.858754, 151.229596));
// Use the builder to create a FindAutocompletePredictionsRequest.
FindAutocompletePredictionsRequest request = FindAutocompletePredictionsRequest.builder()
// Call either setLocationBias() OR setLocationRestriction().
   .setLocationBias(bounds)
   //.setLocationRestriction(bounds)
   .setCountry("au")
   .setTypesFilter(Arrays.asList(PlaceTypes.ADDRESS))
   .setSessionToken(token)
   .setQuery(query)
   .build();

placesClient.findAutocompletePredictions(request).addOnSuccessListener((response) -> {
   for (AutocompletePrediction prediction : response.getAutocompletePredictions()) {
       Log.i(TAG, prediction.getPlaceId());
       Log.i(TAG, prediction.getPrimaryText(null).toString());
   }
}).addOnFailureListener((exception) -> {
   if (exception instanceof ApiException) {
       ApiException apiException = (ApiException) exception;
       Log.e(TAG, "Place not found: " + apiException.getStatusCode());
   }
});

Tokeny sesji

Tokeny sesji grupują fazy zapytania i wyboru użytkownika w oddzielną sesję na potrzeby rozliczeń. Zalecamy używanie tokenów sesji we wszystkich sesjach autouzupełniania. Sesja zaczyna się, gdy użytkownik zaczyna wpisywać zapytanie, a kończy się, gdy wybiera miejsce. Każda sesja może składać się z wielu zapytań, a następnie wybrać jedno miejsce. Po zakończeniu sesji token traci ważność. Aplikacja musi wygenerować nowy token dla każdej sesji.

Maski pól

W metodach zwracających informacje o miejscach musisz określić, jakie typy danych o miejscach mają być zwracane w odpowiedzi na każde żądanie. Dzięki temu będziemy mieć pewność, że żądasz tylko danych, których rzeczywiście używasz. (i płacisz za nie).

Aby określić, które typy danych mają być zwracane, przekaż w elemencie FetchPlaceRequest tablicę o wartości Place.Field, jak w tym przykładzie:

// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.ADDRESS,
                                              Place.Field.ID,
                                              Place.Field.PHONE_NUMBER);

Możesz użyć jednego lub kilku z tych pól:

  • Place.Field.ADDRESS
  • Place.Field.ID
  • Place.Field.LAT_LNG
  • Place.Field.NAME
  • Place.Field.OPENING_HOURS
  • Place.Field.PHONE_NUMBER
  • Place.Field.PHOTO_METADATAS
  • Place.Field.PLUS_CODE
  • Place.Field.PRICE_LEVEL
  • Place.Field.RATING
  • Place.Field.TYPES
  • Place.Field.USER_RATINGS_TOTAL
  • Place.Field.VIEWPORT
  • Place.Field.WEBSITE_URI

Dowiedz się więcej o kodach SKU danych Miejsc.

Aktualizacje selektora miejsc i autouzupełniania

W tej sekcji opisano zmiany wprowadzone w widżetach Miejsc (Selektor miejsc i autouzupełnianie).

Autouzupełnianie automatyczne

Wprowadzono te zmiany w funkcji autouzupełniania:

  • Nazwa aplikacji PlaceAutocomplete została zmieniona na Autocomplete.
    • Nazwa aplikacji PlaceAutocomplete.getPlace została zmieniona na Autocomplete.getPlaceFromIntent.
    • Nazwa aplikacji PlaceAutocomplete.getStatus została zmieniona na Autocomplete.getStatusFromIntent.
  • Nazwa elementu PlaceAutocomplete.RESULT_ERROR została zmieniona na AutocompleteActivity.RESULT_ERROR (obsługa błędów fragmentu autouzupełniania NIE zmieniła się).

Selektor miejsc

Selektor miejsc został wycofany 29 stycznia 2019 r. Została wyłączona 29 lipca 2019 r. i nie jest już dostępna. Dalsze korzystanie z nich spowoduje wyświetlenie komunikatu o błędzie. Nowy pakiet SDK nie obsługuje selektora miejsc.

Autouzupełnianie widżetów

Zaktualizowano widżety autouzupełniania:

  • Prefiks Place został usunięty ze wszystkich zajęć.
  • Dodano obsługę tokenów sesji. Widżet automatycznie zarządza tokenami w tle.
  • Dodaliśmy obsługę masek pól, które umożliwiają wybór typów danych o miejscach zwracanych po dokonaniu wyboru przez użytkownika.

W poniższych sekcjach znajdziesz informacje o tym, jak dodać widżet autouzupełniania do projektu.

Umieszczanie elementu AutocompleteFragment

Aby dodać fragment autouzupełniania, wykonaj następujące czynności:

  1. Dodaj fragment do układu XML aktywności, jak w tym przykładzie.

    <fragment
      android:id="@+id/autocomplete_fragment"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:name=
    "com.google.android.libraries.places.widget.AutocompleteSupportFragment"
      />
    
  2. Aby dodać widżet autouzupełniania do aktywności, wykonaj te czynności:

    • Zainicjuj Places, przekazując kontekst aplikacji i klucz interfejsu API.
    • Zainicjuj AutocompleteSupportFragment.
    • Wywołaj setPlaceFields(), aby wskazać typy danych o miejscach, które chcesz uzyskać.
    • Dodaj polecenie PlaceSelectionListener, aby wykonać działanie z wynikiem oraz obsługiwać ewentualne błędy.

    Poniższy przykład pokazuje dodawanie widżetu autouzupełniania do działania:

    /**
     * Initialize Places. For simplicity, the API key is hard-coded. In a production
     * environment we recommend using a secure mechanism to manage API keys.
     */
    if (!Places.isInitialized()) {
        Places.initialize(getApplicationContext(), "YOUR_API_KEY");
    }
    
    // Initialize the AutocompleteSupportFragment.
    AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
            getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);
    
    autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.NAME));
    
    autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
        @Override
        public void onPlaceSelected(Place place) {
            // TODO: Get info about the selected place.
            Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
        }
    
        @Override
        public void onError(Status status) {
            // TODO: Handle the error.
            Log.i(TAG, "An error occurred: " + status);
        }
    });
    

Używaj intencji do uruchamiania działania autouzupełniania

  1. Inicjuj Places, przekazując kontekst aplikacji i klucz interfejsu API
  2. Użyj Autocomplete.IntentBuilder, aby utworzyć intencję przekazującą wybrany tryb PlaceAutocomplete (pełnoekranowy lub nakładka). Intencja musi wywołać startActivityForResult, przekazując kod żądania, który identyfikuje Twoją intencję.
  3. Zastąp wywołanie zwrotne onActivityResult, aby odebrać wybrane miejsce.

Z przykładu poniżej dowiesz się, jak za pomocą intencji uruchomić autouzupełnianie, a następnie przetworzyć jego wynik:

    /**
     * Initialize Places. For simplicity, the API key is hard-coded. In a production
     * environment we recommend using a secure mechanism to manage API keys.
     */
    if (!Places.isInitialized()) {
        Places.initialize(getApplicationContext(), "YOUR_API_KEY");
    }

    ...

    // Set the fields to specify which types of place data to return.
    List<Place.Field> fields = Arrays.asList(Place.Field.ID, Place.Field.NAME);

    // Start the autocomplete intent.
    Intent intent = new Autocomplete.IntentBuilder(
            AutocompleteActivityMode.FULLSCREEN, fields)
            .build(this);
    startActivityForResult(intent, AUTOCOMPLETE_REQUEST_CODE);

    ...

    /**
     * Override the activity's onActivityResult(), check the request code, and
     * do something with the returned place data (in this example its place name and place ID).
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                Place place = Autocomplete.getPlaceFromIntent(data);
                Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
            } else if (resultCode == AutocompleteActivity.RESULT_ERROR) {
                // TODO: Handle the error.
                Status status = Autocomplete.getStatusFromIntent(data);
                Log.i(TAG, status.getStatusMessage());
            } else if (resultCode == RESULT_CANCELED) {
                // The user canceled the operation.
            }
        }
    }

Selektor miejsc nie jest już dostępny

Selektor miejsc został wycofany 29 stycznia 2019 r. Została wyłączona 29 lipca 2019 r. i nie jest już dostępna. Dalsze korzystanie z nich spowoduje wyświetlenie komunikatu o błędzie. Nowy pakiet SDK nie obsługuje selektora miejsc.