Puoi utilizzare l'oggetto GoogleApiClient
("Client API di Google") per accedere alle API di Google fornite nella libreria di Google Play Services (come Accedi con Google, Giochi e Drive). Il client API di Google fornisce un punto di ingresso comune a Google Play Services e gestisce la connessione di rete tra il dispositivo dell'utente e ogni servizio Google.
Tuttavia, la più recente interfaccia di GoogleApi
e le sue implementazioni sono più facili da usare e sono il modo migliore per accedere alle API Play Services.
Consulta la sezione Accesso alle API di Google.
Questa guida illustra come:
- Gestisci automaticamente la connessione a Google Play Services.
- Consente di effettuare chiamate API sincrone e asincrone a qualsiasi servizio Google Play.
- Gestisci manualmente la connessione a Google Play Services nei rari casi in cui è necessario. Per saperne di più, consulta Connessioni gestite manualmente.
Per iniziare, devi prima installare la libreria Google Play Services (revisione 15 o successiva) per l'SDK Android. Se non l'hai ancora fatto, segui le istruzioni in Configurare l'SDK Google Play Services.
Avvia una connessione gestita automaticamente
Dopo aver collegato il progetto alla libreria di Google Play Services, crea un'istanza di GoogleApiClient
utilizzando le API GoogleApiClient.Builder
nel metodo onCreate()
dell'attività. La classe GoogleApiClient.Builder
fornisce metodi che ti consentono di specificare le API di Google che vuoi utilizzare e gli ambiti OAuth 2.0 desiderati. Ecco un esempio di codice che crea un'istanza GoogleApiClient
che si connette al servizio Google Drive:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .build();
Puoi aggiungere più API e più ambiti allo stesso
GoogleApiClient
aggiungendo ulteriori chiamate a addApi()
e addScope()
.
Importante: se aggiungi l'API Wearable
insieme ad altre API a
GoogleApiClient
, potresti riscontrare errori di connessione client sui dispositivi in
cui non è installata l'app Wear OS. Per evitare errori di connessione, chiama il metodo addApiIfAvailable()
e passa l'API Wearable
per consentire al tuo client di gestire agevolmente l'API mancante. Per ulteriori informazioni, vedi Accedere all'API Wearable.
Per avviare una connessione gestita automaticamente, devi specificare un'implementazione per l'interfaccia OnConnectionFailedListener
in modo da ricevere errori di connessione non risolvibili. Quando l'istanza GoogleApiClient
autogestita tenta di connettersi alle API di Google, mostrerà automaticamente la UI per tentare di risolvere eventuali errori di connessione risolvibili (ad esempio, se Google Play Services deve essere aggiornato). Se si verifica un errore che non può essere risolto, riceverai una chiamata al numero onConnectionFailed()
.
Puoi anche specificare un'implementazione facoltativa per l'interfaccia di ConnectionCallbacks
se la tua app deve sapere quando viene stabilita o sospesa la connessione gestita automaticamente. Ad esempio, se
la tua app effettua chiamate per scrivere dati nelle API di Google, queste devono essere richiamate
solo dopo la chiamata del metodo onConnected()
.
Di seguito è riportata un'attività di esempio che implementa le interfacce di callback e le aggiunge al client API di 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 // ... } }
L'istanza GoogleApiClient
si connetterà automaticamente dopo la chiamata dell'attività
a onStart()
e si disconnetterà dopo aver chiamato onStop()
.
La tua app può iniziare subito a effettuare richieste di lettura alle API di Google dopo aver creato GoogleApiClient
, senza attendere il completamento della connessione.
Comunicare con i servizi Google
Dopo la connessione, il client può effettuare chiamate di lettura e scrittura utilizzando le API specifiche del servizio per le quali la tua app è autorizzata, come specificato dalle API e dagli ambiti che hai aggiunto all'istanza GoogleApiClient
.
Nota: prima di effettuare chiamate a servizi Google specifici, potresti dover registrare la tua app in Google Developer Console. Per le istruzioni, consulta la guida introduttiva appropriata per l'API in uso, ad esempio Google Drive o Accedi con Google.
Quando esegui una richiesta di lettura o scrittura utilizzando GoogleApiClient
, il client API restituisce un oggetto PendingResult
che rappresenta la richiesta.
Ciò si verifica immediatamente, prima che la richiesta venga consegnata al servizio Google chiamato dalla tua app.
Ad esempio, ecco una richiesta per leggere un file da Google Drive che fornisce un oggetto PendingResult
:
Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, filename)); PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);
Quando la tua app dispone di un oggetto PendingResult
,
l'app può specificare se la richiesta deve essere gestita come una chiamata asincrona o una chiamata sincrona.
Suggerimento:la tua app può accodare le richieste di lettura quando non è connessa a Google Play Services. Ad
esempio, la tua app può richiamare metodi per leggere un file da Google Drive a prescindere dal fatto che la tua istanza GoogleApiClient
sia ancora connessa. Dopo aver stabilito una connessione, vengono eseguite le richieste di lettura accodati. Le richieste di scrittura generano un errore se l'app chiama i metodi di scrittura di Google Play Services mentre il client API di Google non è connesso.
Utilizzo delle chiamate asincrone
Per rendere la richiesta asincrona, chiama
setResultCallback()
sul PendingResult
e fornisci un
implementazione dell'interfaccia
ResultCallback
. Ad esempio, ecco la richiesta eseguita in modo asincrono:
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 l'app riceve un oggetto Result
nel callback onResult()
, viene pubblicato come istanza della sottoclasse appropriata, come specificato dall'API in uso, ad esempio DriveApi.MetadataBufferResult
.
Utilizzo delle chiamate sincrone
Se vuoi che il codice venga eseguito in un ordine rigorosamente definito, forse perché il risultato di una chiamata è necessario come argomento per un'altra, puoi rendere sincrona la richiesta chiamando await()
su PendingResult
. Questo blocca il thread e restituisce l'oggetto Result
al completamento della richiesta. Questo oggetto viene pubblicato come istanza della sottoclasse appropriata come specificato
dall'API in uso, ad esempio
DriveApi.MetadataBufferResult
.
Poiché la chiamata a await()
blocca il thread finché non arriva il risultato, la tua app non dovrebbe mai effettuare richieste sincrone alle API di Google nel thread dell'interfaccia utente. La tua app può creare un nuovo thread utilizzando un oggetto AsyncTask
e utilizzarlo per effettuare la richiesta sincrona.
Nell'esempio seguente viene illustrato come effettuare una richiesta di file a Google Drive come chiamata sincrona:
private void loadFile(String filename) { new GetFileTask().execute(filename); } private class GetFileTask extends AsyncTask{ 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 // ... } }
Accedi all'API Wearable
L'API Wearable fornisce un canale di comunicazione per le app eseguite su dispositivi portatili e indossabili. L'API è composta da un insieme di oggetti di dati che il sistema può inviare e sincronizzare e da ascoltatori che informano le tue app di eventi importanti utilizzando un livello dati. L'API Wearable è disponibile sui dispositivi con Android 4.3 (livello API 18) o versioni successive quando un dispositivo indossabile è connesso e l'app complementare Wear OS è installata sul dispositivo.
Utilizzo dell'API Wearable in modalità autonoma
Se la tua app utilizza l'API Wearable ma non altre API Google, puoi aggiungere questa API
chiamando il metodo addApi()
. L'esempio seguente mostra come aggiungere
l'API Wearable alla tua istanza GoogleApiClient
:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Wearable.API) .build();
In situazioni in cui l'API Wearable non è disponibile, le richieste di connessione
che includono l'API Wearable non vanno a buon fine e viene generato il
codice di errore API_UNAVAILABLE
.
L'esempio seguente mostra come determinare se l'API Wearable è disponibile:
// 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 } // ... }
Utilizzare l'API Wearable con altre API di Google
Se la tua app utilizza l'API Wearable oltre ad altre API di Google, chiama il metodo
addApiIfAvailable()
e passa l'API Wearable per verificare se è disponibile. Puoi usare questo controllo per aiutare la tua app a gestire agevolmente i casi in cui l'API non è disponibile.
L'esempio seguente mostra come accedere all'API Wearable insieme all'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();
Nell'esempio precedente, GoogleApiClient
può connettersi correttamente a
Google Drive senza connettersi all'API Wearable se non è disponibile. Dopo aver connesso l'istanza GoogleApiClient
, assicurati che l'API Wearable sia disponibile prima di effettuare le chiamate API:
boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);
Ignorare gli errori di connessione all'API
Se chiami addApi()
e GoogleApiClient
non riesce a
connettersi correttamente a quell'API, l'intera operazione di connessione per quel client non andrà a buon fine e
attiva il callback onConnectionFailed()
.
Puoi registrare un errore di connessione API da ignorare utilizzando addApiIfAvailable()
. Se un'API aggiunta con addApiIfAvailable()
non riesce a connettersi a causa di un errore non recuperabile (come API_UNAVAILABLE
per Wear), l'API viene rimossa da GoogleApiClient
e il client procede a connettersi ad altre API. Tuttavia, se una connessione API ha esito negativo a causa di un errore recuperabile (come un intent di risoluzione del consenso OAuth), l'operazione di connessione del client non andrà a buon fine. Quando
utilizzi una connessione gestita automaticamente, GoogleApiClient
tenterà
di risolvere questo tipo di errori, se possibile. Quando utilizzi una connessione gestita manualmente, un elemento ConnectionResult
contenente un intent di risoluzione viene inviato al callback onConnectionFailed()
. Gli errori di connessione dell'API vengono ignorati solo se non esiste una risoluzione per l'errore e se l'API è stata aggiunta con addApiIfAvailable()
.
Per scoprire come implementare la gestione manuale degli errori di connessione, consulta Gestire gli errori di connessione.
Poiché le API aggiunte con addApiIfAvailable()
potrebbero non essere sempre presenti nell'istanza GoogleApiClient
connessa, devi proteggere le chiamate a queste API aggiungendo un controllo utilizzando hasConnectedApi()
. Per scoprire perché
un'API specifica non è riuscita a connettersi quando l'intera operazione di connessione è riuscita per il client, chiama
getConnectionResult()
e recupera il codice di errore dall'oggetto
ConnectionResult
. Se il client chiama un'API quando non è connessa al client, la chiamata non va a buon fine con il codice di stato API_NOT_AVAILABLE
.
Se l'API che aggiungi tramite addApiIfAvailable()
richiede uno o più ambiti, aggiungili come parametri nella chiamata al metodo addApiIfAvailable()
anziché utilizzare il metodo addScope()
. Gli ambiti aggiunti con questo approccio potrebbero non essere richiesti se la connessione
dell'API non va a buon fine prima di ottenere il consenso OAuth, mentre gli ambiti aggiunti con
addScope()
vengono sempre richiesti.
Connessioni gestite manualmente
La maggior parte di questa guida mostra come utilizzare il metodo enableAutoManage
per avviare una connessione gestita automaticamente con errori risolti automaticamente. In quasi tutti i casi, questo è il modo migliore e più semplice per connettersi alle API di Google dall'app Android. Tuttavia, esistono alcune situazioni in cui è consigliabile utilizzare una connessione gestita manualmente alle API di Google nella tua app:
- Per accedere alle API di Google al di fuori di un'attività o mantenere il controllo della connessione API
- Per personalizzare la gestione e la risoluzione degli errori di connessione
Questa sezione fornisce esempi di questi e altri casi d'uso avanzati.
Avviare una connessione gestita manualmente
Per avviare una connessione gestita manualmente a GoogleApiClient
, devi specificare un'implementazione per le interfacce di callback ConnectionCallbacks
e OnConnectionFailedListener
.
Queste interfacce ricevono callback in risposta al metodo connect()
asincrono quando la connessione a Google Play Services ha esito positivo, ha esito negativo o viene sospesa.
mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build()
Quando gestisci una connessione manualmente, devi chiamare i metodi
connect()
e
disconnect()
nei punti giusti del ciclo di vita della tua app. Nel contesto di un'attività, la best practice prevede la chiamata a connect()
nel metodo onStart()
dell'attività e a disconnect()
nel metodo onStop()
dell'attività.
I metodi connect()
e
disconnect()
vengono chiamati automaticamente quando viene utilizzata una connessione gestita automaticamente.
Se usi GoogleApiClient
per connetterti alle API che richiedono l'autenticazione, come Google Drive o Google Play Giochi, è molto probabile che il primo tentativo di connessione non vada a buon fine e la tua app riceverà una chiamata all'indirizzo onConnectionFailed()
con l'errore SIGN_IN_REQUIRED
perché l'account utente non è stato specificato.
Gestire gli errori di connessione
Quando la tua app riceve una chiamata al callback onConnectionFailed()
, devi chiamare hasResolution()
sull'oggetto ConnectionResult
fornito. Se restituisce true, la tua app può richiedere all'utente di intraprendere un'azione immediata per risolvere l'errore
chiamando startResolutionForResult()
sull'oggetto ConnectionResult
.
In questa situazione, il metodo startResolutionForResult()
si comporta come startActivityForResult()
e avvia un'attività appropriata al contesto che aiuta l'utente a risolvere l'errore (ad esempio un'attività che aiuta l'utente a
selezionare un account).
Se hasResolution()
restituisce false, la tua app deve chiamare
GoogleApiAvailability.getErrorDialog()
,
passando il codice di errore a questo metodo. Verrà restituito un elemento Dialog
fornito da Google Play Services appropriato per l'errore. La finestra di dialogo potrebbe fornire semplicemente un messaggio che spiega l'errore oppure potrebbe anche fornire un'azione per avviare un'attività in grado di risolvere l'errore (ad esempio quando l'utente deve installare una versione più recente di Google Play Services).
Ad esempio, il metodo di callback di onConnectionFailed()
ora dovrebbe avere il seguente aspetto:
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(); } } }
Dopo che l'utente ha completato la finestra di dialogo fornita da
startResolutionForResult()
o ha ignorato il messaggio fornito da GoogleApiAvailability.getErrorDialog()
,
la tua attività riceve la richiamata
onActivityResult()
con il
RESULT_OK
codice risultato.
L'app potrà quindi chiamare di nuovo
connect()
.
Ad esempio:
@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(); } } } }
Nel codice riportato sopra, probabilmente avrai notato il valore booleano mResolvingError
. In questo modo viene monitorato lo stato dell'app mentre l'utente risolve l'errore, per evitare tentativi ripetuti di risoluzione dello stesso errore. Ad esempio, mentre viene visualizzata la finestra di dialogo del selettore account per aiutare l'utente a risolvere l'errore SIGN_IN_REQUIRED
, l'utente può ruotare lo schermo. Questa operazione ricrea l'attività e causa una nuova chiamata del metodo onStart()
, che a sua volta richiama connect()
. Questo comporta un'altra chiamata a startResolutionForResult()
, che crea un'altra finestra di dialogo del selettore account davanti a quella esistente.
Questo valore booleano serve allo scopo previsto solo se persiste nelle istanze di attività. La sezione successiva spiega come mantenere lo stato di gestione degli errori dell'app nonostante altri eventi o azioni dell'utente che si verifichino sul dispositivo.
Mantieni lo stato durante la risoluzione di un errore
Per evitare di eseguire il codice in
onConnectionFailed()
mentre è in corso un precedente tentativo di risoluzione di un errore, devi conservare un valore booleano che registri
se la tua app sta già tentando di risolvere un errore.
Come mostrato nell'esempio di codice riportato sopra, la tua app deve impostare un valore booleano su true
ogni volta che chiama startResolutionForResult()
o visualizza la finestra di dialogo di GoogleApiAvailability.getErrorDialog()
.
Poi, quando la tua app riceve RESULT_OK
nel callback onActivityResult()
, imposta il valore booleano su false
.
Per tenere traccia dei valori booleani nei riavvii delle attività (ad esempio quando l'utente ruota lo schermo), salva il valore booleano nei dati dell'istanza salvata nell'attività utilizzando 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); }
Quindi, recupera lo stato salvato durante
onCreate()
:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... mResolvingError = savedInstanceState != null && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false); }
Ora puoi eseguire in sicurezza l'app e connetterti manualmente a Google Play Services.