É possível usar o objeto GoogleApiClient
("Google API Client")
para acessar as APIs do Google fornecidas na biblioteca de serviços do Google Play, como o Login do Google, Games e Drive. O cliente da API do Google fornece um
ponto de entrada comum aos serviços do Google Play e gerencia a conexão de rede
entre o dispositivo do usuário e cada serviço do Google.
No entanto, a interface GoogleApi
mais recente e as implementações dela são mais fáceis de
usar e são a maneira preferida de acessar as APIs do Google Play Services.
Consulte Como acessar as APIs do Google.
Neste guia, mostramos como:
- Gerenciar automaticamente sua conexão com os Serviços do Google Play.
- Realizar chamadas de API síncronas e assíncronas para qualquer um dos serviços do Google Play.
- Gerenciar manualmente sua conexão com os Serviços do Google Play nos casos raros em que isso for necessário. Para saber mais, consulte Conexões gerenciadas manualmente.
Para começar, primeiro instale a biblioteca do Google Play Services (revisão 15 ou mais recente) para o SDK do Android. Siga as instruções em Configurar o SDK do Google Play Services, caso ainda não tenha feito isso.
Iniciar uma conexão gerenciada automaticamente
Depois que o projeto for vinculado à biblioteca do Google Play Services, crie uma instância de
GoogleApiClient
usando as APIs
GoogleApiClient.Builder
no método
onCreate()
da atividade. A classe
GoogleApiClient.Builder
oferece métodos que permitem especificar as APIs do Google que você quer usar e os escopos
do OAuth 2.0 desejados. Confira um exemplo de código que cria uma instância GoogleApiClient
que se conecta ao serviço do Google Drive:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .build();
É possível adicionar várias APIs e vários escopos ao mesmo
GoogleApiClient
anexando outras chamadas a addApi()
e addScope()
.
Importante:se você adicionar a API Wearable
com outras APIs a um
GoogleApiClient
, poderá encontrar erros de conexão do cliente em dispositivos que
não têm o app Wear OS instalado. Para
evitar erros de conexão, chame o método addApiIfAvailable()
e transmita a
API Wearable
para permitir que o cliente processe a API ausente
corretamente. Para mais informações, consulte Acessar a API Wearable.
Para iniciar uma conexão gerenciada automaticamente, especifique uma implementação para a interface OnConnectionFailedListener
para receber erros de conexão irresolúveis. Quando a instância
GoogleApiClient
gerenciada automaticamente tenta se conectar às APIs do Google, ela mostra automaticamente
a interface para tentar corrigir falhas de conexão solucionáveis, por exemplo, se
os Serviços do Google Play precisarem ser atualizados. Se ocorrer um erro que não pode ser
resolvido, você vai receber uma chamada para
onConnectionFailed()
.
Você também pode especificar uma implementação opcional para a interface ConnectionCallbacks
se o app precisar saber quando a
conexão gerenciada automaticamente for estabelecida ou suspensa. Por exemplo, se
o app fizer chamadas para gravar dados nas APIs do Google, elas só serão invocadas
depois que o método onConnected()
for chamado.
Confira um exemplo de atividade que implementa as interfaces de callback e as adiciona ao cliente da API Google:
import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; import gms.drive.*; import android.support.v4.app.FragmentActivity; public class MyActivity extends FragmentActivity implements OnConnectionFailedListener { private GoogleApiClient mGoogleApiClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create a GoogleApiClient instance mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .build(); // ... } @Override public void onConnectionFailed(ConnectionResult result) { // An unresolvable error has occurred and a connection to Google APIs // could not be established. Display an error message, or handle // the failure silently // ... } }
A instância de GoogleApiClient
vai se conectar automaticamente depois que a atividade
chamar onStart()
e se desconectar depois de chamar onStop()
.
O app pode começar a fazer
solicitações de leitura para as APIs do Google imediatamente após criar GoogleApiClient
, sem
esperar a conexão ser concluída.
Comunicar com os Serviços do Google
Depois de se conectar, o cliente poderá fazer chamadas de leitura e gravação usando as APIs específicas do serviço para
o qual o app está autorizado, conforme especificado pelas APIs e pelos escopos adicionados à instância
GoogleApiClient
.
Observação:antes de fazer chamadas para serviços específicos do Google, talvez seja necessário registrar seu app no Google Developers Console. Para instruções, consulte o guia de início de uso adequado para a API que você está usando, como o Google Drive ou o Login do Google.
Quando você realiza uma solicitação de leitura ou gravação usando GoogleApiClient
, o cliente da API retorna um objeto PendingResult
que representa a solicitação.
Isso ocorre imediatamente, antes que a solicitação seja enviada ao serviço do Google que o app está chamando.
Por exemplo, aqui está uma solicitação para ler um arquivo do Google Drive que fornece um
objeto PendingResult
:
Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, filename)); PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);
Depois que o app tiver um objeto PendingResult
,
ele poderá especificar se a solicitação é processada como uma chamada assíncrona ou síncrona.
Dica:o app pode enfileirar solicitações de leitura enquanto não está conectado ao Google Play Services. Por
exemplo, o app pode chamar métodos para ler um arquivo do Google Drive, mesmo que a instância GoogleApiClient
ainda não esteja conectada. Depois que uma conexão é estabelecida, as solicitações de leitura na fila são executadas. As solicitações de gravação geram um erro se o app chamar
os métodos de gravação dos Serviços do Google Play enquanto o cliente da API do Google não estiver conectado.
Como usar chamadas assíncronas
Para tornar a solicitação assíncrona, chame
setResultCallback()
no PendingResult
e forneça uma
implementação da interface
ResultCallback
. Por
exemplo, confira a solicitação executada de forma assíncrona:
private void loadFile(String filename) { // Create a query for a specific filename in Drive. Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, filename)) .build(); // Invoke the query asynchronously with a callback method Drive.DriveApi.query(mGoogleApiClient, query) .setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() { @Override public void onResult(DriveApi.MetadataBufferResult result) { // Success! Handle the query result. // ... } }); }
Quando o app recebe um objeto Result
no
callback onResult()
,
ele é entregue como uma instância da subclasse adequada, conforme especificado pela API que você está usando,
como
DriveApi.MetadataBufferResult
.
Usar chamadas síncronas
Se você quiser que o código seja executado em uma ordem estritamente definida, talvez porque o resultado de uma
chamada seja necessário como um argumento para outra, é possível tornar a solicitação síncrona chamando
await()
no
PendingResult
. Isso bloqueia a linha de execução
e retorna o objeto Result
quando a
solicitação é concluída. Esse objeto é entregue como uma instância da subclasse apropriada, conforme especificado pela
API que você está usando, por exemplo,
DriveApi.MetadataBufferResult
.
Como a chamada de await()
bloqueia a linha de execução até que o resultado chegue, o app nunca deve fazer solicitações síncronas para as APIs do Google na
linha de execução da interface. O app pode criar uma nova linha de execução usando um objeto AsyncTask
e usar essa linha de execução para fazer a solicitação síncrona.
O exemplo a seguir mostra como fazer uma solicitação de arquivo para o Google Drive como uma chamada síncrona:
private void loadFile(String filename) { new GetFileTask().execute(filename); } private class GetFileTask extends AsyncTask<String, Void, Void> { protected void doInBackground(String filename) { Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, filename)) .build(); // Invoke the query synchronously DriveApi.MetadataBufferResult result = Drive.DriveApi.query(mGoogleApiClient, query).await(); // Continue doing other stuff synchronously // ... } }
Acessar a API Wearable
A API Wearable oferece um canal de comunicação para apps executados em dispositivos portáteis e wearables. A API consiste em um conjunto de objetos de dados que o sistema pode enviar e sincronizar, além de listeners que notificam os apps sobre eventos importantes usando uma camada de dados. A API Wearable está disponível em dispositivos com o Android 4.3 (nível 18 da API) ou mais recente quando um dispositivo wearable está conectado e o app complementar do Wear OS está instalado no dispositivo.
Como usar a API Wearable de forma independente
Se o app usar a API Wearable, mas não outras APIs do Google, será possível adicioná-la
chamando o método addApi()
. O exemplo a seguir mostra como adicionar a
API Wearable à sua instância GoogleApiClient
:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Wearable.API) .build();
Em situações em que a API Wearable não está disponível, as solicitações de conexão que
incluem a API Wearable falham com o
código de erro
API_UNAVAILABLE
.
O exemplo abaixo mostra como determinar se a API Wearable está disponível:
// Connection failed listener method for a client that only // requests access to the Wearable API @Override public void onConnectionFailed(ConnectionResult result) { if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) { // The Wearable API is unavailable } // ... }
Como usar a API Wearable com outras APIs do Google
Se o app usar a API Wearable além de outras APIs do Google, chame o método
addApiIfAvailable()
e transmita a API Wearable para verificar se ela está disponível. Você pode usar essa verificação para ajudar seu app a processar casos em que a API está indisponível.
O exemplo a seguir mostra como acessar a API Wearable com a API Drive:
// Create a GoogleApiClient instance mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Drive.API) .addApiIfAvailable(Wearable.API) .addScope(Drive.SCOPE_FILE) .build();
No exemplo acima, o GoogleApiClient
pode se conectar ao
Google Drive sem se conectar à API Wearable, se ela estiver indisponível. Depois
de conectar a instância do GoogleApiClient
, verifique se a API Wearable está disponível antes de fazer as chamadas de API:
boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);
Ignorar falhas de conexão da API
Se você chamar addApi()
e o GoogleApiClient
não conseguir
se conectar à API, toda a operação de conexão para esse cliente falhará e
acionará o callback onConnectionFailed()
.
É possível registrar uma falha de conexão de API para ser ignorada usando
addApiIfAvailable()
. Se uma API adicionada com
addApiIfAvailable()
não conseguir se conectar devido a um erro não recuperável
(como API_UNAVAILABLE
para Wear),
essa API será descartada do GoogleApiClient
e o cliente vai se conectar
a outras APIs. No entanto, se qualquer conexão de API falhar com um erro recuperável (como uma
intent de resolução de consentimento do OAuth), a operação de conexão do cliente falhará. Ao
usar uma conexão gerenciada automaticamente, o GoogleApiClient
tentará
resolver esses erros quando possível. Ao usar uma conexão gerenciada manualmente,
um ConnectionResult
contendo uma intent de resolução é
enviado para o callback onConnectionFailed()
. As falhas de conexão
da API são ignoradas somente se não houver uma resolução para a falha
e a API tiver sido adicionada
com addApiIfAvailable()
.
Para saber como implementar o processamento manual de falhas de conexão, consulte Processar falhas de conexão.
Como as APIs adicionadas com
addApiIfAvailable()
nem sempre estão presentes na instância
GoogleApiClient
conectada, é necessário proteger as chamadas a essas APIs adicionando uma verificação
usando hasConnectedApi()
. Para descobrir por que uma
API específica não conseguiu se conectar quando toda a operação de conexão teve sucesso para o cliente, chame
getConnectionResult()
e receba o código de erro do objeto
ConnectionResult
. Se o cliente chamar uma API quando ela não estiver
conectada ao cliente, a chamada falhará com o código de status
API_NOT_AVAILABLE
.
Se a API que você está adicionando por addApiIfAvailable()
exigir um ou
mais escopos, adicione esses escopos como parâmetros na
chamada de método addApiIfAvailable()
em vez de usar o método
addScope()
. Os escopos adicionados usando essa abordagem podem não ser solicitados se a conexão
da API falhar antes de receber o consentimento do OAuth, enquanto os escopos adicionados com
addScope()
são sempre solicitados.
Conexões gerenciadas manualmente
A maior parte deste guia mostra como usar o método
enableAutoManage
para iniciar uma
conexão gerenciada automaticamente com erros resolvidos automaticamente. Em quase
todos os casos, essa é a melhor e mais fácil maneira de se conectar às APIs do Google no seu
app Android. No entanto, há algumas situações em que você pode querer usar uma
conexão gerenciada manualmente para as APIs do Google no seu app:
- Para acessar as APIs do Google fora de uma atividade ou manter o controle da conexão da API
- Para personalizar o processamento e a resolução de erros de conexão
Esta seção apresenta exemplos desses e de outros casos de uso avançados.
Iniciar uma conexão gerenciada manualmente
Para iniciar uma conexão gerenciada manualmente para GoogleApiClient
, é necessário
especificar uma implementação para as interfaces de callback,
ConnectionCallbacks
e OnConnectionFailedListener
.
Essas interfaces recebem callbacks em resposta ao método assíncrono
connect()
quando a
conexão com os serviços do Google Play é bem-sucedida, falha ou é suspensa.
mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build()
Ao gerenciar uma conexão manualmente, é necessário chamar os métodos
connect()
e
disconnect()
nos pontos certos do ciclo de vida do app. Em um contexto de
atividade, a prática recomendada é chamar connect()
no método onStart()
da atividade e disconnect()
no método onStop()
da atividade.
Os métodos connect()
e
disconnect()
são chamados automaticamente ao usar uma conexão gerenciada automaticamente.
Se você estiver usando GoogleApiClient
para se conectar a APIs que exigem
autenticação, como o Google Drive ou o Google Play Games, é provável
que a primeira tentativa de conexão falhe e que o app receba uma chamada
para onConnectionFailed()
com o erro SIGN_IN_REQUIRED
porque a conta do usuário não foi especificada.
Processar falhas de conexão
Quando o app receber uma chamada para o callback onConnectionFailed()
, chame hasResolution()
no objeto ConnectionResult
fornecido. Se ele retornar verdadeiro, o app poderá solicitar que o usuário tome medidas imediatas para resolver o erro chamando
startResolutionForResult()
no objeto ConnectionResult
.
O método startResolutionForResult()
se comporta da mesma forma que startActivityForResult()
nessa situação,
e inicia uma atividade adequada ao contexto que ajuda o usuário a resolver o erro, como uma atividade que ajuda o usuário a
selecionar uma conta.
Se hasResolution()
retornar falso, o app precisará chamar
GoogleApiAvailability.getErrorDialog()
,
transmitindo o código de erro para esse método. Isso retorna um
Dialog
fornecido pelos serviços do Google Play
que é adequado ao erro. A caixa de diálogo pode simplesmente fornecer uma mensagem explicando
o erro ou uma ação para iniciar uma atividade que possa resolver o erro, como quando o usuário precisa instalar uma versão mais recente do Google Play Services.
Por exemplo, o método de callback
onConnectionFailed()
agora vai ficar assim:
public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener { // Request code to use when launching the resolution activity private static final int REQUEST_RESOLVE_ERROR = 1001; // Unique tag for the error dialog fragment private static final String DIALOG_ERROR = "dialog_error"; // Bool to track whether the app is already resolving an error private boolean mResolvingError = false; // ... @Override public void onConnectionFailed(ConnectionResult result) { if (mResolvingError) { // Already attempting to resolve an error. return; } else if (result.hasResolution()) { try { mResolvingError = true; result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR); } catch (SendIntentException e) { // There was an error with the resolution intent. Try again. mGoogleApiClient.connect(); } } else { // Show dialog using GoogleApiAvailability.getErrorDialog() showErrorDialog(result.getErrorCode()); mResolvingError = true; } } // The rest of this code is all about building the error dialog /* Creates a dialog for an error message */ private void showErrorDialog(int errorCode) { // Create a fragment for the error dialog ErrorDialogFragment dialogFragment = new ErrorDialogFragment(); // Pass the error that should be displayed Bundle args = new Bundle(); args.putInt(DIALOG_ERROR, errorCode); dialogFragment.setArguments(args); dialogFragment.show(getSupportFragmentManager(), "errordialog"); } /* Called from ErrorDialogFragment when the dialog is dismissed. */ public void onDialogDismissed() { mResolvingError = false; } /* A fragment to display an error dialog */ public static class ErrorDialogFragment extends DialogFragment { public ErrorDialogFragment() { } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // Get the error code and retrieve the appropriate dialog int errorCode = this.getArguments().getInt(DIALOG_ERROR); return GoogleApiAvailability.getInstance().getErrorDialog( this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR); } @Override public void onDismiss(DialogInterface dialog) { ((MyActivity) getActivity()).onDialogDismissed(); } } }
Depois que o usuário conclui a caixa de diálogo fornecida por
startResolutionForResult()
ou dispensa a mensagem fornecida por GoogleApiAvailability.getErrorDialog()
,
sua atividade recebe o callback
onActivityResult()
com o código de resultado
RESULT_OK
.
O app pode chamar
connect()
novamente.
Exemplo:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_RESOLVE_ERROR) { mResolvingError = false; if (resultCode == RESULT_OK) { // Make sure the app is not already connected or attempting to connect if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); } } } }
No código acima, você provavelmente notou o booleano mResolvingError
. Isso rastreia o
estado do app enquanto o usuário resolve o erro para evitar tentativas repetidas de resolver o mesmo
erro. Por exemplo, enquanto a caixa de diálogo do seletor de contas é mostrada para ajudar o usuário a resolver o
erro SIGN_IN_REQUIRED
, ele pode girar a tela. Isso recria sua atividade e faz com que o método
onStart()
seja
chamado novamente, o que chama
connect()
novamente. Isso
resulta em outra chamada para
startResolutionForResult()
,
que cria outra caixa de diálogo do seletor de conta na frente da caixa de diálogo atual.
Esse booleano serve ao propósito pretendido somente se persistir nas instâncias de atividade. A próxima seção explica como manter o estado de processamento de erros do app, apesar de outras ações do usuário ou eventos que ocorrem no dispositivo.
Manter o estado ao resolver um erro
Para evitar a execução do código em
onConnectionFailed()
enquanto uma tentativa anterior de resolver um erro está em andamento, é necessário manter um booleano que
monitora se o app já está tentando resolver um erro.
Conforme mostrado no exemplo de código acima, o app precisa definir um booleano como true
sempre que chamar
startResolutionForResult()
ou mostrar a caixa de diálogo de
GoogleApiAvailability.getErrorDialog()
.
Em seguida, quando o app receber
RESULT_OK
no callback
onActivityResult()
, defina o booleano como false
.
Para acompanhar o booleano em reinicializações de atividades (como quando o usuário gira a tela),
salve o booleano nos dados de instância salvos da atividade usando
onSaveInstanceState()
:
private static final String STATE_RESOLVING_ERROR = "resolving_error"; @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError); }
Em seguida, recupere o estado salvo durante
onCreate()
:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... mResolvingError = savedInstanceState != null && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false); }
Agora você pode executar o app com segurança e se conectar manualmente aos Serviços do Google Play.