Eseguire la migrazione al client SDK New Places

Questa guida illustra le differenze tra la libreria di compatibilità di Places e la nuova versione autonoma di Places SDK for Android. Se hai utilizzato la libreria di compatibilità di Places anziché eseguire la migrazione alla nuova versione autonoma di Places SDK for Android, questa guida ti mostra come aggiornare i tuoi progetti per utilizzare la nuova versione di Places SDK for Android.

L'unico modo per accedere alle funzionalità e alle correzioni di bug in Places SDK for Android superiore alla versione 2.6.0 sarà utilizzare Places SDK for Android. Google consiglia di eseguire l'aggiornamento dalla libreria di compatibilità alla nuova versione di Places SDK for Android il prima possibile.

Che cosa è cambiato?

Le principali aree di cambiamento sono le seguenti:

  • La nuova versione di Places SDK for Android viene distribuita come libreria client statica. Prima di gennaio 2019, l'SDK Places for Android era disponibile tramite Google Play Services. Da allora, è stata fornita una libreria di compatibilità di Places per semplificare la transizione al nuovo SDK Places per Android.
  • Esistono metodi completamente nuovi.
  • Le maschere di campo sono ora supportate per i metodi che restituiscono dettagli sul luogo. Puoi utilizzare le maschere di campo per specificare quali tipi di dati dei luoghi restituire.
  • I codici di stato utilizzati per segnalare gli errori sono stati migliorati.
  • Il completamento automatico ora supporta i token di sessione.
  • Il selettore di luoghi non è più disponibile.

Informazioni sulla raccolta di compatibilità di Places

A gennaio 2019, con il rilascio della versione 1.0 dell'SDK Places per Android autonomo, Google ha fornito una libreria di compatibilità per facilitare la migrazione dalla versione ritirata di Google Play Services dell'SDK Places per Android (com.google.android.gms:play-services-places).

Questa libreria di compatibilità è stata fornita temporaneamente per reindirizzare e tradurre le chiamate API destinate alla versione di Google Play Services alla nuova versione autonoma finché gli sviluppatori non hanno potuto eseguire la migrazione del codice per utilizzare i nuovi nomi nell'SDK autonomo. Per ogni versione dell'API Places SDK for Android che è stata rilasciata dalla versione 1.0 alla versione 2.6.0, è stata rilasciata una versione corrispondente della libreria di compatibilità di Places per fornire funzionalità equivalenti.

Blocco e ritiro della libreria di compatibilità di Places

Tutte le versioni della libreria di compatibilità per l'SDK Places per Android sono state ritirate a partire dal 31 marzo 2022. La versione 2.6.0 è l'ultima versione della libreria di compatibilità di Places. L'unico modo per accedere alle funzionalità e alle correzioni di bug in Places SDK for Android versione 2.6.0 e successive sarà utilizzare Places SDK for Android.

Google consiglia di eseguire la migrazione a Places SDK for Android per accedere alle nuove funzionalità e alle correzioni di bug critiche per le release successive alla versione 2.6.0. Se al momento utilizzi la libreria di compatibilità, segui i passaggi riportati di seguito nella sezione Installare Places SDK for Android per eseguire la migrazione a Places SDK for Android.

installa la libreria client

La nuova versione di Places SDK for Android viene distribuita come libreria client statica.

Utilizza Maven per aggiungere l'SDK Places per Android al tuo progetto Android Studio:

  1. Se al momento utilizzi la libreria di compatibilità di Places:

    1. Sostituisci la seguente riga nella sezione dependencies:

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

      Con questa riga per passare all'SDK Places per Android:

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

  2. Se al momento utilizzi la versione di Places SDK for Android di Play Services:

    1. Sostituisci la seguente riga nella sezione dependencies:

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

      Con questa riga per passare all'SDK Places per Android:

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

  3. Sincronizza il progetto Gradle.

  4. Imposta minSdkVersion per il progetto dell'applicazione su 16 o versioni successive.

  5. Aggiorna gli asset "Creato da 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. Compila l'app. Se visualizzi errori di compilazione a causa della conversione a Places SDK per Android, consulta le sezioni riportate di seguito per informazioni su come risolvere questi errori.

Inizializzare il nuovo client dell'SDK Places

Inizializza il nuovo client SDK di Places come mostrato nel seguente esempio:

// 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);

Codici di stato

Il codice di stato per gli errori relativi al limite QPS è cambiato. Ora gli errori relativi al limite di QPS vengono riportati tramite PlaceStatusCodes.OVER_QUERY_LIMIT. Non sono più previsti limiti di QPD.

Sono stati aggiunti i seguenti codici stato:

  • REQUEST_DENIED: la richiesta è stata rifiutata. Di seguito sono elencati alcuni possibili motivi:

    • Non è stata fornita alcuna chiave API.
    • È stata fornita una chiave API non valida.
    • L'API Places non è stata abilitata nella console Cloud.
    • È stata fornita una chiave API con limitazioni errate.
  • INVALID_REQUEST: la richiesta non è valida a causa di un argomento mancante o non valido.

  • NOT_FOUND: nessun risultato trovato per la richiesta specificata.

Nuovi metodi

La nuova versione di Places SDK for Android introduce metodi completamente nuovi, progettati per garantire coerenza. Tutti i nuovi metodi rispettano quanto segue:

  • Gli endpoint non utilizzano più il verbo get.
  • Gli oggetti di richiesta e risposta condividono lo stesso nome del corrispondente metodo client.
  • Gli oggetti Request ora hanno dei builder; i parametri obbligatori vengono passati come parametri del builder della richiesta.
  • I buffer non vengono più utilizzati.

Questa sezione illustra i nuovi metodi e il loro funzionamento.

Recuperare un luogo tramite ID

Utilizza fetchPlace() per ottenere i dettagli di un determinato luogo. fetchPlace() funziona in modo simile a getPlaceById().

Per recuperare un luogo:

  1. Chiama fetchPlace(), passando un oggetto FetchPlaceRequest che specifica un ID luogo e un elenco di campi che specificano i dati del luogo da restituire.

    // 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.DISPLAY_NAME);
    
    // Construct a request object, passing the place ID and fields array.
    FetchPlaceRequest request = FetchPlaceRequest.builder(placeId, placeFields)
            .build();
    
    
  2. Chiama addOnSuccessListener() per gestire il problema FetchPlaceResponse. Viene restituito un singolo risultato 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());
        }
    });
    

Recuperare una foto di un luogo

Usa fetchPhoto() per ottenere una foto di un luogo. fetchPhoto() restituisce le foto di un luogo. La procedura per richiedere una foto è stata semplificata. Ora puoi richiedere PhotoMetadata direttamente dall'oggetto Place; non è più necessaria una richiesta separata. Le foto possono avere una larghezza o un'altezza massima di 1600 pixel. Le funzioni fetchPhoto() funzionano in modo simile a getPhoto().

Per recuperare le foto dei luoghi:

  1. Configura una chiamata al numero fetchPlace(). Assicurati di includere il PHOTO_METADATAS campo nella richiesta:

    List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
    
  2. Recupera un oggetto Place (in questo esempio viene utilizzato fetchPlace(), ma puoi anche utilizzare findCurrentPlace()):

    FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
    
  3. Aggiungi un OnSuccessListener per ottenere i metadati della foto dal Place risultante nel FetchPlaceResponse, quindi utilizza i metadati della foto risultanti per ottenere un bitmap e un testo di attribuzione:

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

Trovare un luogo dalla posizione dell'utente

Utilizza findCurrentPlace() per trovare la posizione attuale del dispositivo dell'utente. findCurrentPlace() restituisce un elenco di PlaceLikelihood che indicano i luoghi in cui è più probabile che si trovi il dispositivo dell'utente. findCurrentPlace() funziona in modo simile a getCurrentPlace().

Per ottenere la posizione attuale del dispositivo dell'utente:

  1. Assicurati che la tua app richieda le autorizzazioni ACCESS_FINE_LOCATION e ACCESS_WIFI_STATE. L'utente deve concedere l'autorizzazione per accedere alla posizione corrente del dispositivo. Per maggiori dettagli, consulta Richiedi autorizzazioni per le app.

  2. Crea un FindCurrentPlaceRequest, incluso un elenco di tipi di dati dei luoghi da recuperare.

      // Use fields to define the data types to return.
      List<Place.Field> placeFields = Arrays.asList(Place.Field.DISPLAY_NAME);
    
      // Use the builder to create a FindCurrentPlaceRequest.
      FindCurrentPlaceRequest request =
              FindCurrentPlaceRequest.builder(placeFields).build();
    
  3. Chiama findCurrentPlace e gestisci la risposta, controllando prima che l'utente abbia concesso l'autorizzazione a utilizzare la posizione del dispositivo.

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

Trovare le previsioni di completamento automatico

Utilizza findAutocompletePredictions() per restituire le previsioni relative ai luoghi in risposta alle query di ricerca degli utenti. findAutocompletePredictions() funziona in modo simile a getAutocompletePredictions().

L'esempio seguente mostra la chiamata a 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());
   }
});

Token di sessione

I token di sessione raggruppano le fasi di query e selezione di una ricerca dell'utente in una sessione distinta a fini di fatturazione. Ti consigliamo di utilizzare i token di sessione per tutte le sessioni di completamento automatico. La sessione inizia quando l'utente inizia a digitare una query e termina quando seleziona un luogo. Ogni sessione può avere più query, seguite dalla selezione di un luogo. Al termine di una sessione, il token non è più valido; l'app deve generare un nuovo token per ogni sessione.

Maschere di campo

Nei metodi che restituiscono i dettagli dei luoghi, devi specificare i tipi di dati sul luogo da restituire con ogni richiesta. In questo modo puoi assicurarti di richiedere (e pagare) solo i dati che utilizzerai effettivamente.

Per specificare i tipi di dati da restituire, passa un array di Place.Field in FetchPlaceRequest, come mostrato nell'esempio seguente:

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

Per un elenco dei campi che puoi utilizzare in una maschera di campo, consulta Campi di dati dei luoghi (novità) .

Scopri di più sugli SKU dei dati di Places.

Aggiornamenti di Ricerca luoghi e Compilazione automatica

Questa sezione spiega le modifiche apportate ai widget Luoghi (Selettore di luoghi e completamento automatico).

Completamento automatico programmatico

Sono state apportate le seguenti modifiche al completamento automatico:

  • Il nuovo nome di PlaceAutocomplete è Autocomplete.
    • Il nuovo nome di PlaceAutocomplete.getPlace è Autocomplete.getPlaceFromIntent.
    • Il nuovo nome di PlaceAutocomplete.getStatus è Autocomplete.getStatusFromIntent.
  • PlaceAutocomplete.RESULT_ERROR è stato rinominato in AutocompleteActivity.RESULT_ERROR (la gestione degli errori per il frammento di completamento automatico NON è cambiata).

Selettore di luoghi

Il selettore di luoghi è stato ritirato il 29 gennaio 2019. È stata disattivata il 29 luglio 2019 e non è più disponibile. L'utilizzo continuato comporterà un messaggio di errore. Il nuovo SDK non supporta il selettore di luoghi.

Widget di completamento automatico

I widget di completamento automatico sono stati aggiornati:

  • Il prefisso Place è stato rimosso da tutti i corsi.
  • È stato aggiunto il supporto per i token di sessione. Il widget gestisce automaticamente i token in background.
  • È stato aggiunto il supporto delle maschere di campo, che ti consentono di scegliere i tipi di dati dei luoghi da restituire dopo che l'utente ha effettuato una selezione.

Le sezioni seguenti mostrano come aggiungere un widget di completamento automatico al progetto.

Incorporare un AutocompleteFragment

Per aggiungere un frammento di completamento automatico:

  1. Aggiungi un frammento al layout XML dell'attività, come mostrato nell'esempio seguente.

    <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. Per aggiungere il widget di completamento automatico all'attività:

    • Inizializza Places passando il contesto dell'applicazione e la tua chiave API.
    • Inizializza AutocompleteSupportFragment.
    • Chiama setPlaceFields() per indicare i tipi di dati dei luoghi che vuoi recuperare.
    • Aggiungi un PlaceSelectionListener per fare qualcosa con il risultato, nonché per gestire eventuali errori che potrebbero verificarsi.

    L'esempio seguente mostra l'aggiunta di un widget di completamento automatico a un'attività:

    /**
     * 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.DISPLAY_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);
        }
    });
    

Utilizzare un'intenzione per avviare l'attività di completamento automatico

  1. Inizializza Places passando il contesto dell'app e la tua chiave API
  2. Utilizza Autocomplete.IntentBuilder per creare un intent, passando la modalitàPlaceAutocomplete desiderata (a schermo intero o sovrapposta). L'intent deve chiamare startActivityForResult, passando un codice richiesta che identifica il tuo intent.
  3. Sostituisci il callback onActivityResult per ricevere il luogo selezionato.

L'esempio seguente mostra come utilizzare un'intenzione per avviare il completamento automatico e gestire il risultato:

    /**
     * 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.DISPLAY_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.
            }
        }
    }

Il selettore di luoghi non è più disponibile

Il selettore di luoghi è stato ritirato il 29 gennaio 2019. È stata disattivata il 29 luglio 2019 e non è più disponibile. L'utilizzo continuato comporterà un messaggio di errore. Il nuovo SDK non supporta il selettore di luoghi.