Accéder aux API Google avec GoogleApiClient (obsolète)

Vous pouvez utiliser l'objet GoogleApiClient ("Client API Google") pour accéder aux API Google fournies dans la bibliothèque des services Google Play (par exemple, Google Sign-In, Jeux et Drive). Le client API Google fournit un point d'entrée commun aux services Google Play et gère la connexion réseau entre l'appareil de l'utilisateur et chaque service Google.

Cependant, la nouvelle interface GoogleApi et ses implémentations sont plus faciles à utiliser et constituent le moyen privilégié pour accéder aux API des services Play. Consultez la section Accéder aux API Google.

Ce guide vous explique comment:

  • Gérez automatiquement votre connexion aux services Google Play.
  • Effectuez des appels d'API synchrones et asynchrones vers n'importe quel service Google Play.
  • Gérez manuellement votre connexion aux services Google Play dans les rares cas où cela est nécessaire. Pour en savoir plus, consultez Connexions gérées manuellement.
Figure 1: Illustration montrant comment le client API Google fournit une interface permettant de se connecter et d'appeler les services Google Play disponibles, tels que Google Play Jeux et Google Drive.

Pour commencer, vous devez d'abord installer la bibliothèque de services Google Play (révision 15 ou ultérieure) pour votre SDK Android. Si vous ne l'avez pas déjà fait, suivez les instructions de la section Configurer le SDK des services Google Play.

Démarrer une connexion gérée automatiquement

Une fois votre projet associé à la bibliothèque de services Google Play, créez une instance de GoogleApiClient à l'aide des API GoogleApiClient.Builder dans la méthode onCreate() de votre activité. La classe GoogleApiClient.Builder fournit des méthodes qui vous permettent de spécifier les API Google que vous souhaitez utiliser et les champs d'application OAuth 2.0 souhaités. Voici un exemple de code qui crée une instance GoogleApiClient qui se connecte au service Google Drive:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Drive.API)
    .addScope(Drive.SCOPE_FILE)
    .build();

Vous pouvez ajouter plusieurs API et plusieurs champs d'application au même GoogleApiClient en ajoutant des appels supplémentaires à addApi() et addScope().

Important:Si vous ajoutez l'API Wearable avec d'autres API à une GoogleApiClient, vous risquez de rencontrer des erreurs de connexion client sur les appareils sur lesquels l'application Wear OS n'est pas installée. Pour éviter les erreurs de connexion, appelez la méthode addApiIfAvailable() et transmettez l'API Wearable afin de permettre à votre client de gérer correctement l'API manquante. Pour en savoir plus, consultez Accéder à l'API Wearable.

Pour démarrer une connexion gérée automatiquement, vous devez spécifier une implémentation pour l'interface OnConnectionFailedListener afin de recevoir les erreurs de connexion insolubles. Lorsque votre instance GoogleApiClient gérée automatiquement tente de se connecter aux API Google, elle affiche automatiquement l'UI pour tenter de résoudre les échecs de connexion pouvant être résolus (par exemple, si les services Google Play doivent être mis à jour). Si une erreur ne peut pas être résolue, vous recevrez un appel à onConnectionFailed().

Vous pouvez également spécifier une implémentation facultative pour l'interface ConnectionCallbacks si votre application doit savoir quand la connexion gérée automatiquement est établie ou suspendue. Par exemple, si votre application effectue des appels pour écrire des données dans les API Google, ceux-ci ne doivent être appelés qu'après l'appel de la méthode onConnected().

Voici un exemple d'activité qui implémente les interfaces de rappel et les ajoute au client 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

        // ...
    }
}

Votre instance GoogleApiClient se connectera automatiquement après l'appel d'activité onStart() et se déconnectera après avoir appelé onStop(). Votre application peut immédiatement commencer à envoyer des requêtes de lecture aux API Google après la création de GoogleApiClient, sans attendre la fin de la connexion.

Communiquer avec les services Google

Une fois connecté, votre client peut effectuer des appels en lecture et en écriture à l'aide des API spécifiques au service pour lesquelles votre application est autorisée, comme spécifié par les API et les niveaux d'accès que vous avez ajoutés à votre instance GoogleApiClient.

Remarque:Avant d'appeler des services Google spécifiques, vous devrez peut-être d'abord enregistrer votre application dans la Google Play Console. Pour obtenir des instructions, reportez-vous au guide de démarrage correspondant à l'API que vous utilisez, par exemple Google Drive ou Google Sign-In.

Lorsque vous effectuez une requête de lecture ou d'écriture à l'aide de GoogleApiClient, le client API renvoie un objet PendingResult qui représente la requête. Cela se produit immédiatement, avant que la requête ne soit envoyée au service Google que votre application appelle.

Par exemple, voici une requête permettant de lire un fichier Google Drive qui fournit un objet PendingResult:

Query query = new Query.Builder()
        .addFilter(Filters.eq(SearchableField.TITLE, filename));
PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);

Une fois que votre application dispose d'un objet PendingResult, elle peut spécifier si la requête est gérée comme un appel asynchrone ou synchrone.

Conseil:Votre application peut mettre les requêtes de lecture en file d'attente lorsqu'elle n'est pas connectée aux services Google Play. Par exemple, votre application peut appeler des méthodes pour lire un fichier à partir de Google Drive, que votre instance GoogleApiClient soit déjà connectée ou non. Une fois la connexion établie, les requêtes de lecture mises en file d'attente s'exécutent. Les requêtes d'écriture génèrent une erreur si votre application appelle les méthodes d'écriture des services Google Play alors que votre client API Google n'est pas connecté.

Utiliser des appels asynchrones

Pour rendre la requête asynchrone, appelez setResultCallback() sur PendingResult et fournissez une implémentation de l'interface ResultCallback. Par exemple, voici la requête exécutée de manière asynchrone:

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

Lorsque votre application reçoit un objet Result dans le rappel onResult(), il est envoyé en tant qu'instance de la sous-classe appropriée spécifiée par l'API que vous utilisez, telle que DriveApi.MetadataBufferResult.

Utiliser des appels synchrones

Si vous souhaitez que votre code s'exécute dans un ordre strictement défini, peut-être parce que le résultat d'un appel est nécessaire en tant qu'argument vers un autre, vous pouvez rendre votre requête synchrone en appelant await() au niveau de PendingResult. Cela bloque le thread et renvoie l'objet Result une fois la requête terminée. Cet objet est diffusé en tant qu'instance de la sous-classe appropriée, comme spécifié par l'API que vous utilisez, par exemple DriveApi.MetadataBufferResult.

Étant donné que l'appel de await() bloque le thread jusqu'à l'arrivée du résultat, votre application ne doit jamais envoyer de requêtes synchrones aux API Google sur le thread UI. Votre application peut créer un thread à l'aide d'un objet AsyncTask et l'utiliser pour effectuer la requête synchrone.

L'exemple suivant montre comment envoyer une requête de fichier à Google Drive sous la forme d'un appel synchrone:

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

Accéder à l'API Wearable

L'API Wearable fournit un canal de communication pour les applications qui s'exécutent sur des accessoires connectés ou portables. L'API se compose d'un ensemble d'objets de données que le système peut envoyer et synchroniser, et d'écouteurs qui informent vos applications d'événements importants à l'aide d'une couche de données. L'API Wearable est disponible sur les appareils équipés d'Android 4.3 (niveau d'API 18) ou version ultérieure lorsqu'un accessoire connecté est connecté et que l'application associée Wear OS est installée sur l'appareil.

Utiliser la version autonome de l'API Wearable

Si votre application utilise l'API Wearable, mais pas d'autres API Google, vous pouvez ajouter cette API en appelant la méthode addApi(). L'exemple suivant montre comment ajouter l'API Wearable à votre instance GoogleApiClient:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Wearable.API)
    .build();

Dans les cas où l'API Wearable n'est pas disponible, les requêtes de connexion qui incluent l'API Wearable échouent avec le code d'erreur API_UNAVAILABLE.

L'exemple suivant montre comment déterminer si l'API Wearable est disponible:

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

Utiliser l'API Wearable avec d'autres API Google

Si votre application utilise l'API Wearable en plus d'autres API Google, appelez la méthode addApiIfAvailable() et transmettez l'API Wearable pour vérifier si elle est disponible. Vous pouvez utiliser cette vérification pour aider votre application à gérer correctement les cas où l'API n'est pas disponible.

L'exemple suivant montre comment accéder à l'API Wearable avec l'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();

Dans l'exemple ci-dessus, GoogleApiClient peut se connecter à Google Drive sans se connecter à l'API Wearable si elle n'est pas disponible. Une fois que vous avez connecté votre instance GoogleApiClient, assurez-vous que l'API Wearable est disponible avant d'effectuer les appels d'API:

boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);

Ignorer les échecs de connexion aux API

Si vous appelez addApi() et que GoogleApiClient ne parvient pas à se connecter à cette API, toute l'opération de connexion pour ce client échoue et déclenche le rappel onConnectionFailed().

Vous pouvez enregistrer un échec de connexion API à ignorer à l'aide de addApiIfAvailable(). Si une API ajoutée avec addApiIfAvailable() ne parvient pas à se connecter en raison d'une erreur non récupérable (comme API_UNAVAILABLE pour Wear), cette API est supprimée de votre GoogleApiClient et le client se connecte à d'autres API. Toutefois, si une connexion API échoue avec une erreur récupérable (comme un intent de résolution du consentement OAuth), l'opération de connexion client échoue. Lorsque vous utilisez une connexion gérée automatiquement, GoogleApiClient tente de résoudre ces erreurs lorsque cela est possible. Lorsque vous utilisez une connexion gérée manuellement, un ConnectionResult contenant un intent de résolution est envoyé au rappel onConnectionFailed(). Les échecs de connexion à l'API ne sont ignorés que s'il n'y a pas de résolution pour l'échec et si l'API a été ajoutée avec addApiIfAvailable(). Pour découvrir comment mettre en œuvre la gestion manuelle des échecs de connexion, consultez la section Gérer les échecs de connexion.

Étant donné que les API ajoutées avec addApiIfAvailable() ne sont pas toujours présentes dans l'instance GoogleApiClient connectée, vous devez protéger les appels vers ces API en ajoutant une vérification à l'aide de hasConnectedApi(). Pour savoir pourquoi une API particulière n'a pas pu se connecter lorsque l'ensemble de l'opération de connexion a réussi pour le client, appelez getConnectionResult() et obtenez le code d'erreur à partir de l'objet ConnectionResult. Si votre client appelle une API alors qu'elle n'est pas connectée au client, l'appel échoue avec le code d'état API_NOT_AVAILABLE.

Si l'API que vous ajoutez via addApiIfAvailable() nécessite un ou plusieurs champs d'application, ajoutez-les en tant que paramètres dans l'appel de la méthode addApiIfAvailable() plutôt qu'à l'aide de la méthode addScope(). Les champs d'application ajoutés à l'aide de cette approche ne peuvent pas être demandés si la connexion à l'API échoue avant l'obtention du consentement OAuth, tandis que les champs d'application ajoutés avec addScope() sont toujours demandés.

Connexions gérées manuellement

La majeure partie de ce guide vous explique comment utiliser la méthode enableAutoManage pour lancer une connexion gérée automatiquement avec des erreurs résolues automatiquement. Dans presque tous les cas, il s'agit du moyen le plus simple et le plus efficace de vous connecter aux API Google à partir de votre application Android. Toutefois, dans certains cas, vous pouvez utiliser une connexion gérée manuellement aux API Google dans votre application:

  • Pour accéder aux API Google en dehors d'une activité ou garder le contrôle de la connexion aux API
  • Pour personnaliser la gestion et la résolution des erreurs de connexion

Cette section fournit des exemples de ces cas d'utilisation avancés et d'autres cas d'utilisation avancés.

Démarrer une connexion gérée manuellement

Pour initier une connexion gérée manuellement à GoogleApiClient, vous devez spécifier une implémentation pour les interfaces de rappel, ConnectionCallbacks et OnConnectionFailedListener. Ces interfaces reçoivent des rappels en réponse à la méthode connect() asynchrone lorsque la connexion aux services Google Play réussit, échoue ou est suspendue.

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build()

Lorsque vous gérez une connexion manuellement, vous devez appeler les méthodes connect() et disconnect() aux bons points du cycle de vie de votre application. Dans le contexte d'une activité, il est recommandé d'appeler connect() dans la méthode onStart() de votre activité et disconnect() dans la méthode onStop() de votre activité. Les méthodes connect() et disconnect() sont appelées automatiquement lors de l'utilisation d'une connexion gérée automatiquement.

Si vous utilisez GoogleApiClient pour vous connecter à des API nécessitant une authentification, comme Google Drive ou Google Play Jeux, il est possible que votre première tentative de connexion échoue et que votre application reçoive un appel à onConnectionFailed() avec l'erreur SIGN_IN_REQUIRED, car le compte utilisateur n'a pas été spécifié.

Gérer les échecs de connexion

Lorsque votre application reçoit un appel au rappel onConnectionFailed(), vous devez appeler hasResolution() sur l'objet ConnectionResult fourni. Si la valeur est "true", votre application peut demander à l'utilisateur d'agir immédiatement pour résoudre l'erreur en appelant startResolutionForResult() sur l'objet ConnectionResult. Dans ce cas, la méthode startResolutionForResult() se comporte de la même manière que startActivityForResult() et lance une activité adaptée au contexte qui aide l'utilisateur à résoudre l'erreur (telle qu'une activité qui l'aide à sélectionner un compte).

Si hasResolution() renvoie la valeur "false", votre application doit appeler GoogleApiAvailability.getErrorDialog(), en transmettant le code d'erreur à cette méthode. Cela renvoie un Dialog, fourni par les services Google Play, adapté à l'erreur. La boîte de dialogue peut simplement fournir un message expliquant l'erreur ou fournir une action permettant de lancer une activité permettant de résoudre l'erreur (par exemple, lorsque l'utilisateur doit installer une version plus récente des services Google Play).

Par exemple, votre méthode de rappel onConnectionFailed() devrait maintenant se présenter comme suit:

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

Une fois que l'utilisateur a terminé la boîte de dialogue fournie par startResolutionForResult() ou ignoré le message fourni par GoogleApiAvailability.getErrorDialog(), votre activité reçoit le rappel onActivityResult() avec le code de résultat RESULT_OK. Votre application peut ensuite appeler à nouveau connect(). Exemple :

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

Dans le code ci-dessus, vous avez probablement remarqué la valeur booléenne mResolvingError. Cela permet de suivre l'état de l'application pendant que l'utilisateur résout l'erreur afin d'éviter les tentatives répétées de résolution de la même erreur. Par exemple, alors que la boîte de dialogue de l'outil de sélection de comptes s'affiche pour aider l'utilisateur à résoudre l'erreur SIGN_IN_REQUIRED, il peut faire pivoter l'écran. Cela recrée votre activité et entraîne un nouvel appel de votre méthode onStart(), qui appelle à nouveau connect(). Cela entraîne un autre appel à startResolutionForResult(), qui crée une autre boîte de dialogue de sélection de compte devant l'existante.

Cette valeur booléenne ne remplit sa fonction que si elle persiste entre les instances d'activité. La section suivante explique comment conserver l'état de traitement des erreurs de votre application malgré les autres actions ou événements de l'utilisateur qui se produisent sur l'appareil.

Maintenir l'état tout en résolvant une erreur

Pour éviter d'exécuter le code dans onConnectionFailed() lorsqu'une tentative précédente de résolution d'une erreur est en cours, vous devez conserver une valeur booléenne qui suit si votre application tente déjà de résoudre une erreur.

Comme indiqué dans l'exemple de code ci-dessus, votre application doit définir une valeur booléenne sur true chaque fois qu'elle appelle startResolutionForResult() ou affiche la boîte de dialogue de GoogleApiAvailability.getErrorDialog(). Ensuite, lorsque votre application reçoit RESULT_OK dans le rappel onActivityResult(), définissez la valeur booléenne sur false.

Pour suivre la valeur booléenne lors des redémarrages de l'activité (par exemple, lorsque l'utilisateur fait pivoter l'écran), enregistrez la valeur booléenne dans les données d'instance enregistrées de l'activité à l'aide de 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);
}

Ensuite, récupérez l'état enregistré pendant onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...
    mResolvingError = savedInstanceState != null
            && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
}

Vous pouvez maintenant exécuter votre application en toute sécurité et vous connecter manuellement aux services Google Play.