Este guia explica as mudanças entre a biblioteca de compatibilidade do Places e a nova versão independente do SDK do Places para Android. Se você estiver usando a biblioteca de compatibilidade do Places em vez de migrar para a nova versão independente do SDK do Places para Android, este guia mostra como atualizar seus projetos para usar a nova versão do SDK do Places para Android.
A única maneira de acessar os recursos e as correções de bugs no SDK do Places para Android versão 2.6.0 e posteriores é usar o SDK do Places para Android. O Google recomenda atualizar da biblioteca de compatibilidade para a nova versão do SDK do Places para Android assim que possível.
Erro: 9005 PLACES_API_RATE_LIMIT_EXCEEDED
O que mudou?
As principais áreas de mudança são:
- A nova versão do SDK do Places para Android é distribuída como uma biblioteca de cliente estática. Antes de janeiro de 2019, o SDK do Places para Android era disponibilizado pelo Google Play Services. Desde então, uma biblioteca de compatibilidade do Places foi fornecida para facilitar a transição para o novo SDK do Places para Android.
- Há métodos totalmente novos.
- Agora há suporte para máscaras de campo em métodos que retornam detalhes de lugar. É possível usar máscaras de campo para especificar quais tipos de dados de lugar retornar.
- Os códigos de status usados para informar erros foram aprimorados.
- O preenchimento automático agora é compatível com tokens de sessão.
- O Place Picker não está mais disponível.
Sobre a biblioteca de compatibilidade do Places
Em janeiro de 2019, com o lançamento da versão 1.0 do SDK independente do Places para Android, o Google disponibilizou uma biblioteca de compatibilidade para ajudar na migração da versão desativada do SDK do Places para Android do Google Play Services (com.google.android.gms:play-services-places
).
Essa biblioteca de compatibilidade foi fornecida temporariamente para redirecionar e traduzir chamadas de API destinadas à versão dos serviços do Google Play para a nova versão independente até que os desenvolvedores pudessem migrar o código para usar os novos nomes no SDK independente. Para cada versão do SDK do Places para Android lançada entre a 1.0 e a 2.6.0, uma versão correspondente da biblioteca de compatibilidade do Places foi lançada para oferecer funcionalidade equivalente.
Congelamento e descontinuação da biblioteca de compatibilidade do Places
Todas as versões da biblioteca de compatibilidade do SDK do Places para Android foram descontinuadas em 31 de março de 2022. A versão 2.6.0 é a última da biblioteca de compatibilidade do Places. A única maneira de acessar os recursos e as correções de bugs no SDK do Places para Android versão 2.6.0 e posteriores é usar o SDK do Places para Android.
O Google recomenda migrar para o SDK do Places para Android para acessar novos recursos e correções de bugs críticos em versões acima da 2.6.0. Se você estiver usando a biblioteca de compatibilidade, siga as etapas abaixo na seção Instalar o SDK do Places para Android para migrar para o SDK do Places para Android.
Instale a biblioteca de cliente
A nova versão do SDK do Places para Android é distribuída como uma biblioteca de cliente estática.
Use o Maven para adicionar o SDK Places para Android ao seu projeto do Android Studio:
Se você estiver usando a biblioteca de compatibilidade do Places:
Substitua a seguinte linha na seção
dependencies
:implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'
Com esta linha para mudar para o SDK do Places para Android:
implementation("com.google.android.libraries.places:places:4.3.1")
Se você estiver usando a versão do SDK do Places para Android do Google Play Services:
Substitua a seguinte linha na seção
dependencies
:implementation 'com.google.android.gms:play-services-places:X.Y.Z'
Com esta linha para mudar para o SDK do Places para Android:
implementation("com.google.android.libraries.places:places:4.3.1")
Sincronize seu projeto do Gradle.
Defina a
minSdkVersion
do projeto de aplicativo como 23 ou mais recente.Atualize os recursos "Tecnologia do 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
Crie o app. Se você encontrar erros de build devido à conversão para o SDK do Places para Android, consulte as seções abaixo para saber como resolver esses erros.
Inicializar o novo cliente do SDK do Places
Inicialize o novo cliente do SDK do Places, conforme mostrado no exemplo a seguir:
// 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);
Códigos de status
O código de status para erros de limite de QPS mudou. Agora, os erros de limite de QPS são retornados via PlaceStatusCodes.OVER_QUERY_LIMIT
. Não há mais limites de QPD.
Os seguintes códigos de status foram adicionados:
REQUEST_DENIED
: a solicitação foi negada. Alguns possíveis motivos para isso:- Nenhuma chave de API foi fornecida.
- Uma chave de API inválida foi fornecida.
- A API Places não foi ativada no console do Cloud.
- Uma chave de API foi fornecida com restrições incorretas.
INVALID_REQUEST
: a solicitação é inválida devido a um argumento ausente ou inválido.NOT_FOUND
: nenhum resultado foi encontrado para a solicitação.
Novos métodos
A nova versão do SDK do Places para Android apresenta métodos totalmente novos, projetados para consistência. Todos os novos métodos obedecem ao seguinte:
- Os endpoints não usam mais o verbo
get
. - Os objetos de solicitação e resposta compartilham o mesmo nome do método do cliente correspondente.
- Os objetos de solicitação agora têm builders. Os parâmetros obrigatórios são transmitidos como parâmetros de solicitação builder.
- Os buffers não são mais usados.
Esta seção apresenta os novos métodos e mostra como eles funcionam.
Extrair um lugar por ID
Use fetchPlace()
para acessar detalhes sobre um lugar específico. As funções fetchPlace()
funcionam de maneira semelhante a
getPlaceById()
.
Siga estas etapas para buscar um lugar:
Chame
fetchPlace()
, transmitindo um objetoFetchPlaceRequest
que especifica um ID de lugar e uma lista de campos que especificam os dados de lugar a serem retornados.// 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();
Chame
addOnSuccessListener()
para processar oFetchPlaceResponse
. Um único resultadoPlace
é retornado.// 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()); } });
Extrair uma foto de lugar
Use fetchPhoto()
para receber uma foto de um lugar. fetchPhoto()
retorna fotos de um lugar. O padrão para pedir uma foto foi simplificado. Agora é possível solicitar PhotoMetadata
diretamente do objeto Place
. Não é mais necessário fazer uma solicitação separada.
As fotos podem ter uma largura ou altura máxima de 1.600 px. As funções fetchPhoto()
funcionam de maneira semelhante a getPhoto()
.
Siga estas etapas para buscar fotos de lugares:
Configure uma chamada para
fetchPlace()
. Inclua o campoPHOTO_METADATAS
na solicitação:List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
Receba um objeto Place. Este exemplo usa
fetchPlace()
, mas você também pode usarfindCurrentPlace()
:FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
Adicione um
OnSuccessListener
para receber os metadados da foto doPlace
resultante noFetchPlaceResponse
. Em seguida, use os metadados da foto resultante para receber um bitmap e um texto de atribuição: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()); } }); });
Encontrar um lugar na localização do usuário
Use findCurrentPlace()
para encontrar a localização atual do dispositivo do usuário. findCurrentPlace()
retorna uma lista de PlaceLikelihood
s indicando os lugares onde o dispositivo do usuário
tem mais probabilidade de estar localizado. A função findCurrentPlace()
funciona de maneira semelhante a getCurrentPlace()
.
Siga estas etapas para receber a localização atual do dispositivo do usuário:
Verifique se o app solicita as permissões
ACCESS_FINE_LOCATION
eACCESS_WIFI_STATE
. O usuário precisa conceder permissão para acessar a localização atual do dispositivo. Consulte Solicitar permissões do app para mais detalhes.Crie um
FindCurrentPlaceRequest
, incluindo uma lista de tipos de dados de lugar a serem retornados.// 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();
Chame findCurrentPlace e processe a resposta, verificando primeiro se o usuário concedeu permissão para usar a localização do 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(); }
Encontrar previsões de preenchimento automático
Use findAutocompletePredictions()
para retornar previsões de lugares em resposta a consultas de pesquisa do usuário.
A função findAutocompletePredictions()
funciona de maneira semelhante a getAutocompletePredictions()
.
O exemplo a seguir mostra como chamar 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());
}
});
Tokens de sessão
Os tokens de sessão agrupam as fases de consulta e seleção de uma pesquisa do usuário em uma sessão discreta para fins de faturamento. Recomendamos o uso de tokens de sessão em todas as sessões de preenchimento automático. A sessão começa quando o usuário começa a digitar uma consulta e termina quando ele seleciona um lugar. Cada sessão pode ter várias consultas, seguidas por uma seleção de lugar. Após a conclusão de uma sessão, o token perde a validade. Seu app precisa gerar um novo token para cada sessão.
Máscaras de campo
Em métodos que retornam detalhes de lugares, você precisa especificar quais tipos de dados retornar com cada solicitação. Isso ajuda a garantir que você só solicite (e pague por) dados que realmente vai usar.
Para especificar quais tipos de dados retornar, transmita uma matriz de Place.Field
s na sua
FetchPlaceRequest
, como mostrado no exemplo a seguir:
// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.FORMATTED_ADDRESS,
Place.Field.ID,
Place.Field.INTERNATIONAL_PHONE_NUMBER);
Para uma lista de campos que podem ser usados em uma máscara de campo, consulte Campos de dados de lugar (novo) .
Leia mais sobre as SKUs de dados do Places.
Atualizações do Place Picker e do Autocomplete
Esta seção explica as mudanças nos widgets do Places (Place Picker e Autocomplete).
Preenchimento automático programático
As seguintes mudanças foram feitas no preenchimento automático:
PlaceAutocomplete
foi renomeado comoAutocomplete
.PlaceAutocomplete.getPlace
foi renomeado comoAutocomplete.getPlaceFromIntent
.PlaceAutocomplete.getStatus
foi renomeado comoAutocomplete.getStatusFromIntent
.
PlaceAutocomplete.RESULT_ERROR
foi renomeado comoAutocompleteActivity.RESULT_ERROR
(o tratamento de erros do fragmento de preenchimento automático NÃO mudou).
Seletor de local
O Place Picker foi descontinuado em 29 de janeiro de 2019. Ele foi desativado em 29 de julho de 2019 e não está mais disponível. O uso contínuo vai resultar em uma mensagem de erro. O novo SDK não é compatível com o seletor de lugar.
Widgets de preenchimento automático
Os widgets de preenchimento automático foram atualizados:
- O prefixo
Place
foi removido de todas as classes. - Adição de suporte a tokens de sessão. O widget gerencia tokens para você automaticamente em segundo plano.
- Adicionamos suporte para máscaras de campo, que permitem escolher quais tipos de dados de lugar retornar depois que o usuário faz uma seleção.
As seções a seguir mostram como adicionar um widget de preenchimento automático ao seu projeto.
Incorporar um AutocompleteFragment
Para adicionar um fragmento de preenchimento automático, siga estas etapas:
Adicione um fragmento ao layout XML da atividade, como mostrado no exemplo a seguir.
<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" />
Para adicionar o widget de preenchimento automático à atividade, siga estas etapas:
- Inicialize o
Places
, transmitindo o contexto do aplicativo e sua chave de API. - Inicialize o
AutocompleteSupportFragment
: - Chame
setPlaceFields()
para indicar os tipos de dados de lugar que você quer receber. - Adicione um
PlaceSelectionListener
para fazer algo com o resultado e tratar os erros que possam ocorrer.
O exemplo abaixo mostra como adicionar um widget de preenchimento automático a uma atividade:
/** * 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); } });
- Inicialize o
Usar uma intent para iniciar a atividade de preenchimento automático
- Inicialize o
Places
, transmitindo o contexto do app e sua chave de API. - Use
Autocomplete.IntentBuilder
para criar uma intent, transmitindo o modoPlaceAutocomplete
desejado (tela cheia ou sobreposição). A intent precisa chamarstartActivityForResult
, transmitindo um código de solicitação que identifica sua intent. - Substitua o callback
onActivityResult
para receber o lugar selecionado.
O exemplo a seguir mostra como usar uma intent para iniciar o preenchimento automático e processar o resultado:
/**
* 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.
}
}
}
O Place Picker não está mais disponível
O Place Picker foi descontinuado em 29 de janeiro de 2019. Ele foi desativado em 29 de julho de 2019 e não está mais disponível. O uso contínuo vai resultar em uma mensagem de erro. O novo SDK não é compatível com o seletor de lugar.