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

Vous pouvez utiliser l'objet GoogleApiClient ("Client de l'API Google") pour accéder aux API Google fournies dans la bibliothèque de services Google Play (telles que Google Sign-In, Jeux et Drive). Le client de l'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.

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

Ce guide vous explique comment:

  • Gérer automatiquement votre connexion aux services Google Play
  • Effectuer des appels d'API synchrones et asynchrones à l'un des services 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 la section Connexions gérées manuellement.
Figure 1: Illustration montrant comment le client de l'API Google fournit une interface permettant de se connecter et d'effectuer des appels à l'un des services Google Play disponibles, tels que Google Play Jeux et Google Drive.

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

Lancer une connexion gérée automatiquement

Une fois votre projet associé à la bibliothèque des 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 à la même GoogleApiClient en ajoutant des appels supplémentaires à addApi() et addScope().

Important:Si vous ajoutez l'API Wearable avec d'autres API à un GoogleApiClient, vous pouvez 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 pour permettre à votre client de gérer correctement l'API manquante. Pour en savoir plus, consultez la section 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 des erreurs de connexion non résolues. Lorsque votre instance GoogleApiClient gérée automatiquement tente de se connecter aux API Google, elle affiche automatiquement l'UI pour tenter de corriger les échecs de connexion pouvant être résolus (par exemple, si les services Google Play doivent être mis à jour). Si une erreur non résolue se produit, 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, elles ne doivent être appelées 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 de l'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 une fois que votre activité aura appelé 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 avoir créé GoogleApiClient, sans attendre la fin de la connexion.

Communiquer avec les services Google

Une fois la connexion établie, 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 indiqué par les API et les portées que vous avez ajoutées à votre instance GoogleApiClient.

Remarque:Avant d'effectuer des appels vers des services Google spécifiques, vous devrez peut-être d'abord enregistrer votre application dans la Google Developers Console. Pour obtenir des instructions, consultez le guide de démarrage approprié pour l'API que vous utilisez, comme Google Drive ou Google Sign-In.

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

Par exemple, voici une requête visant à lire un fichier à partir de 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 en tant qu'appel asynchrone ou synchrone.

Remarque:Votre application peut mettre en file d'attente des requêtes de lecture lorsqu'elle n'est pas connectée aux services Google Play. Par exemple, votre application peut appeler des méthodes pour lire un fichier depuis 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 sont exécutées. 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 d'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 fourni en tant qu'instance de la sous-classe appropriée, comme spécifié par l'API que vous utilisez, par exemple DriveApi.MetadataBufferResult.

Utiliser des appels synchrones

Si vous souhaitez que votre code s'exécute dans un ordre strictement défini, par exemple parce que le résultat d'un appel est nécessaire en tant qu'argument pour un autre, vous pouvez rendre votre requête synchrone en appelant await() sur PendingResult. Cela bloque le thread et renvoie l'objet Result une fois la requête terminée. Cet objet est fourni 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'à ce que le résultat arrive, votre application ne doit jamais effectuer de requêtes synchrones aux API Google sur le thread d'interface utilisateur. Votre application peut créer un thread à l'aide d'un objet AsyncTask et utiliser ce thread pour effectuer la requête synchrone.

L'exemple suivant montre comment envoyer une requête de fichier à Google Drive en tant qu'appel synchrone:

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

Accéder à l'API Wearable

L'API Wearable fournit un canal de communication pour les applications exécutées sur des appareils portables et connectés. L'API se compose d'un ensemble d'objets de données que le système peut envoyer et synchroniser, ainsi que d'écouteurs qui informent vos applications des é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 appareil connecté est connecté et que l'application compagnon Wear OS est installée sur l'appareil.

Utiliser l'API Wearable de manière autonome

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

Lorsque 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 et à 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. Après avoir 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 à l'API

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

Vous pouvez enregistrer un échec de connexion d'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 du 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 de l'API ne sont ignorés que s'il n'existe aucune solution au problème et que l'API a été ajoutée avec addApiIfAvailable(). Pour savoir comment implémenter la gestion manuelle des échecs de connexion, consultez 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 à ces API en ajoutant une vérification à l'aide de hasConnectedApi(). Pour savoir pourquoi une API particulière n'a pas réussi à se connecter alors que l'ensemble de l'opération de connexion a réussi pour le client, appelez getConnectionResult() et obtenez le code d'erreur 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 votre appel de méthode addApiIfAvailable() plutôt qu'en utilisant la méthode addScope(). Les habilitations ajoutées à l'aide de cette approche peuvent ne pas être demandées si la connexion à l'API échoue avant d'obtenir le consentement OAuth, tandis que les habilitations ajoutées avec addScope() sont toujours demandées.

Connexions gérées manuellement

La majeure partie de ce guide vous explique comment utiliser la méthode enableAutoManage pour établir une connexion gérée automatiquement avec des erreurs résolues automatiquement. Dans la plupart des cas, il s'agit du moyen le plus simple et le plus efficace de se connecter aux API Google depuis 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 conserver le contrôle de la connexion de l'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.

Démarrer une connexion gérée manuellement

Pour établir 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 asynchrone connect() 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 moments du cycle de vie de votre application. Dans un contexte d'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 lorsque vous utilisez 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 probable 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 renvoyée est "true", votre application peut demander à l'utilisateur de prendre des mesures immédiates pour résoudre l'erreur en appelant startResolutionForResult() sur l'objet ConnectionResult. Dans cette situation, 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 (par exemple, une activité qui aide l'utilisateur à 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 qui est approprié à l'erreur. La boîte de dialogue peut simplement fournir un message expliquant l'erreur ou une action permettant de lancer une activité qui peut 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 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 pour résoudre la même erreur. Par exemple, lorsque la boîte de dialogue de sélection du compte s'affiche pour aider l'utilisateur à résoudre l'erreur SIGN_IN_REQUIRED, l'utilisateur peut faire pivoter l'écran. Cela recrée votre activité et appelle à nouveau votre méthode onStart(), qui appelle à nouveau connect(). Un autre appel à startResolutionForResult() est alors effectué, ce qui crée une autre boîte de dialogue de sélecteur de compte devant l'existante.

Cette valeur booléenne n'a d'utilité que si elle persiste entre les instances d'activité. La section suivante explique comment conserver l'état de gestion des erreurs de votre application malgré d'autres actions ou événements utilisateur sur l'appareil.

Maintenir l'état lors de la résolution d'une erreur

Pour éviter d'exécuter le code dans onConnectionFailed() alors qu'une tentative précédente de résolution d'une erreur est en cours, vous devez conserver une valeur booléenne qui indique 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 à partir 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 l'indicateur booléen lors des redémarrages de l'activité (par exemple, lorsque l'utilisateur fait pivoter l'écran), enregistrez-le 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);
}

Récupérez ensuite 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.