Cómo acceder a las APIs de Google con GoogleApiClient (obsoleto)

Puedes usar GoogleApiClient ("Cliente de la API de Google") para acceder a las APIs de Google que se proporcionan en la biblioteca de Google Play Services (como Acceso con Google, Juegos y Drive). El cliente de la API de Google proporciona punto de entrada común a Google Play Services y administra la red conexión entre el dispositivo del usuario y cada servicio de Google.

Sin embargo, la interfaz GoogleApi más reciente y sus implementaciones son más fáciles de y son la forma preferida de acceder a las APIs de los Servicios de Play. Consulta Cómo acceder a las APIs de Google.

En esta guía, se muestra cómo puedes hacer lo siguiente:

  • Administra automáticamente tu conexión a los Servicios de Google Play.
  • Realizar llamadas de API síncronas y asíncronas a cualquiera de los Servicios de Google Play
  • Administra manualmente tu conexión a los Servicios de Google Play en los casos excepcionales en que sea necesario. Para obtener más información, consulta Conexiones administradas de forma manual.
Figura 1: Ilustración que muestra cómo el cliente de la API de Google proporciona una interfaz para conectarse y realizar llamadas a cualquiera de los servicios de Google Play disponibles, como Google Play Juegos y Google Drive.

Para comenzar, primero debes instalar la biblioteca de Google Play Services (revisión 15 o posterior) para tu SDK de Android. Si aún no lo has hecho, sigue las instrucciones en Configura el SDK de Servicios de Google Play.

Inicia una conexión administrada automáticamente

Una vez que tu proyecto esté vinculado a la biblioteca de Google Play Services, crea una instancia de GoogleApiClient con el GoogleApiClient.Builder en la configuración de tu onCreate() . El GoogleApiClient.Builder proporciona métodos que te permiten especificar las APIs de Google que quieres usar y las APIs de OAuth 2.0. Este es un ejemplo de código que crea un Instancia de GoogleApiClient que se conecta con el servicio de Google Drive:

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

Puedes agregar varias APIs y varios alcances al mismo GoogleApiClient agregando llamadas adicionales a addApi() y addScope().

Importante: Si agregas la API de Wearable junto con otras APIs a una GoogleApiClient, es posible que se produzcan errores de conexión del cliente en dispositivos que no tener instalada la app para Wear OS Para para evitar errores de conexión, llama al método addApiIfAvailable() y pasa la API de Wearable para que tu cliente pueda manejar correctamente los problemas en la API de Cloud. Para obtener más información, consulta Cómo acceder a la API de Wearable.

Para iniciar una conexión administrada automáticamente, debes especificar una implementación para OnConnectionFailedListener para recibir errores de conexión que no se pueden resolver. Cuando se administran de forma automática La instancia GoogleApiClient intenta conectarse a las APIs de Google, se hará automáticamente de visualización para intentar corregir cualquier falla de conexión que se pueda resolver (por ejemplo, si los Servicios de Google Play deben actualizarse). Si se produce un error que no se puede resuelto, recibirás una llamada para onConnectionFailed()

También puedes especificar una implementación opcional para la interfaz ConnectionCallbacks si tu app necesita saber cuándo se debe cuando se establece o suspende la conexión administrada automáticamente. Por ejemplo, tu app realiza llamadas para escribir datos a las APIs de Google; estos deben invocarse Solo después de que se haya llamado al método onConnected().

Esta es una actividad de ejemplo que implementa las interfaces de devolución de llamada y agrega al cliente de la API de 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

        // ...
    }
}

Tu instancia de GoogleApiClient se conectará automáticamente después de tu actividad llamar a onStart() y desconectarse después de llamar a onStop(). Tu app puede comenzar a hacer cambios de lectura a las APIs de Google después de compilar GoogleApiClient, sin a que se complete la conexión.

Cómo comunicarse con los servicios de Google

Después de conectarte, tu cliente puede realizar llamadas de lectura y escritura usando las APIs específicas del servicio para el que tu aplicación está autorizada, tal como lo especifican las APIs y los alcances que agregaste a tu GoogleApiClient.

Nota: Antes de realizar llamadas a servicios de Google específicos, es posible que primero debas registrar tu app en la Consola para desarrolladores de Google. Para obtener instrucciones, consulta la página de inicio de introducción para la API que estás usando, como Google Drive o Acceso con Google:

Cuando realizas una solicitud de lectura o escritura con GoogleApiClient, el cliente de la API muestra un objeto PendingResult que representa la solicitud. Esto ocurre inmediatamente, antes de que la solicitud se entregue al servicio de Google al que está llamando tu app.

Por ejemplo, esta es una solicitud para leer un archivo de Google Drive que proporciona un Objeto PendingResult:

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

Después de que tu app tenga un objeto PendingResult, haz lo siguiente: tu app puede especificar si la solicitud se maneja como una llamada asíncrona o como una llamada síncrona.

Nota: Tu app puede poner en cola solicitudes de lectura sin estar conectada a los Servicios de Google Play. Para Por ejemplo, tu app puede llamar a métodos para leer un archivo de Google Drive independientemente de si tu instancia de GoogleApiClient ya está conectada. Después de que se establece una conexión, se ejecutan las solicitudes de lectura en cola. Las solicitudes de escritura generan un error si tu app llama Métodos de escritura de los Servicios de Google Play mientras tu cliente de la API de Google no está conectado.

Usa llamadas asíncronas

Para que la solicitud sea asíncrona, llama a setResultCallback() en el objeto PendingResult y proporciona un implementación del ResultCallback. Para Por ejemplo, esta es la solicitud ejecutada de forma así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.
            // ...
        }
    });
}

Cuando tu app recibe un objeto Result en la devolución de llamada onResult() se entrega como una instancia de la subclase correspondiente, tal como lo especifica la API que estás usando, como, por ejemplo, DriveApi.MetadataBufferResult

Usa llamadas síncronas

Si quieres que tu código se ejecute en un orden estrictamente definido, quizás porque el resultado de una se necesita una llamada como argumento para otra, puedes hacer que tu solicitud sea síncrona llamando await() en PendingResult Esto bloqueará el subproceso y devuelve el objeto Result cuando se completa la solicitud. Este objeto se entrega como una instancia de la subclase correspondiente según lo especificado en la API que estás usando, por ejemplo, DriveApi.MetadataBufferResult

Porque llamar a await() bloquea el subproceso hasta que llega el resultado, tu app nunca debe realizar solicitudes síncronas a las APIs de Google en subproceso de IU. Tu app puede crear un subproceso nuevo con un objeto AsyncTask y usarlo para realizar la solicitud síncrona.

En el siguiente ejemplo, se muestra cómo realizar una solicitud de archivo a Google Drive como una llamada síncrona:

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

Accede a la API de Wearable

La API de Wearable proporciona un canal de comunicación para apps que se ejecutan en dispositivos portátiles y wearables. La API consta de un conjunto de objetos de datos que el sistema puede enviar y sincronizar. objetos de escucha que notifican a tus apps sobre eventos importantes mediante una capa de datos. El La API de Wearable está disponible en dispositivos con Android 4.3 (nivel de API 18) o versiones posteriores cuando un dispositivo wearable está conectado y la aplicación complementaria de Wear OS esté instalada en el dispositivo.

Cómo usar la API independiente de Wearable

Si tu app usa la API de Wearable pero no otras APIs de Google, puedes agregar esta API llamando al método addApi(). En el siguiente ejemplo, se muestra cómo agregar API de Wearable a tu instancia de GoogleApiClient:

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

En situaciones en las que la API de Wearable no esté disponible, las solicitudes de conexión que incluir la API de Wearable fallan con el API_UNAVAILABLE código de error.

En el siguiente ejemplo, se muestra cómo determinar si la API de 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
    }
    // ...
}

Cómo usar la API de Wearable con otras APIs de Google

Si tu app usa la API de Wearable además de otras APIs de Google, llama al addApiIfAvailable() y pasa la API de Wearable para verificar si está disponible. Puedes usar esta verificación para ayudar a tu app a manejar correctamente los casos en los que la API no está disponible.

En el siguiente ejemplo, se muestra la manera de acceder a la API de Wearable junto con la API de 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();

En el ejemplo anterior, GoogleApiClient se puede conectar correctamente con Google Drive sin conectarse a la API de Wearable si no está disponible. Después del conecta tu GoogleApiClient asegúrate de que la API de Wearable esté disponible antes de realizar las llamadas a la API:

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

Cómo ignorar errores de conexión de API

Si llamas a addApi(), y GoogleApiClient no puede conectarse correctamente a esa API, la operación de conexión completa para ese cliente falla y activa la devolución de llamada onConnectionFailed().

Puedes registrar una falla de conexión a la API para que se ignore mediante addApiIfAvailable() Si una API agregada con addApiIfAvailable() no se conecta debido a un error irrecuperable (como API_UNAVAILABLE para Wear), esa API se elimina de tu GoogleApiClient y el cliente procede conectarse a otras APIs. Sin embargo, si cualquier conexión a una API falla con un error recuperable (como una el intent de resolución de consentimiento de OAuth), fallará la operación de conexión del cliente. Cuándo con una conexión administrada automáticamente, GoogleApiClient intentará para resolver esos errores cuando sea posible. Cuando usas una conexión administrada de forma manual se muestra un objeto ConnectionResult que contiene un intent de resolución se envía a la devolución de llamada onConnectionFailed(). API las fallas de conexión se ignoran solo si no hay una resolución para la falla. y la API se agregó con addApiIfAvailable(). Para aprender a implementar la falla de conexión manual consulta Soluciona fallas de conexión.

Debido a que las APIs agregadas con Es posible que addApiIfAvailable() no siempre esté presente en el archivo conectado. GoogleApiClient, debes proteger las llamadas a estas APIs agregando una verificación usando hasConnectedApi(). Para averiguar por qué un API específica no pudo conectarse cuando la operación de conexión se realizó correctamente para el cliente, llama getConnectionResult() y obtén el código de error del objeto ConnectionResult. Si tu cliente llama a una API cuando no está conectado al cliente, la llamada falla y muestra el API_NOT_AVAILABLE código de estado.

Si la API que estás agregando a través de addApiIfAvailable() requiere una o más permisos, agrégalos como parámetros en tu addApiIfAvailable(), en lugar de usar la addScope(). Es posible que no se soliciten los permisos agregados con este enfoque si la API antes de obtener el consentimiento para OAuth, mientras que los permisos agregados con addScope() siempre se solicitan.

Conexiones administradas de forma manual

La mayor parte de esta guía te muestra cómo usar la enableAutoManage para iniciar una una conexión administrada automáticamente con errores resueltos automáticamente. En casi en todos los casos, esta es la mejor y la más sencilla para conectarte a las APIs de Google desde tu App para Android Sin embargo, hay algunas situaciones en las que querrás usar un conexión administrada manualmente a las APIs de Google en tu app:

  • Para acceder a las APIs de Google fuera de una actividad o retener el control de la API conexión
  • Para personalizar el manejo y la resolución de errores de conexión

En esta sección, se proporcionan ejemplos de estos y otros casos de uso avanzados.

Inicia una conexión administrada de forma manual

Para iniciar una conexión administrada de forma manual a GoogleApiClient, debes especificar una implementación para las interfaces de devolución de llamada, ConnectionCallbacks y OnConnectionFailedListener. Estas interfaces reciben devoluciones de llamada en respuesta al proceso connect() cuando la conexión a los Servicios de Google Play es exitosa, falla o se suspende.

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

Cuando administres una conexión de forma manual, deberás llamar al connect() y disconnect() en los puntos correctos del ciclo de vida de tu app. En una actividad contexto, la práctica recomendada es llamar a connect() en el onStart() de tu actividad y disconnect() en el método onStop() de tu actividad. El connect() y Métodos disconnect() se llaman automáticamente cuando se usa una conexión administrada automáticamente.

Si usas GoogleApiClient para conectarte a APIs que requieren de Google, como Google Drive o Google Play Juegos, es muy probable tu primer intento de conexión fallará y tu app recibirá una llamada para onConnectionFailed() con el SIGN_IN_REQUIRED porque no se especificó la cuenta de usuario.

Soluciona las fallas de conexión

Cuando tu app recibe una llamada al onConnectionFailed() devolución de llamada, debes llamar a hasResolution() en el ConnectionResult proporcionado . Si devuelve un valor "true", tu app puede solicitar que el usuario tome medidas inmediatas para resolver el error llamando a startResolutionForResult() en el objeto ConnectionResult. Método startResolutionForResult() Se comporta de la misma manera que startActivityForResult() en esta situación. e inicia una actividad adecuada para el contexto que ayuda al usuario a resolver el error (como una actividad que ayuda al usuario a seleccionar una cuenta).

Si es hasResolution() devuelve un valor falso, tu app debe llamar GoogleApiAvailability.getErrorDialog(): y pasar el código de error a este método. Esto muestra un Dialog proporcionado por Google Play servicios adecuados para el error. El diálogo puede simplemente proporcionar un mensaje que explique el error, o también puede proporcionar una acción para iniciar una actividad que resuelva el error (por ejemplo, cuando el usuario necesita instalar una versión más reciente de los Servicios de Google Play).

Por ejemplo, tu El método de devolución de llamada onConnectionFailed() debería verse de la siguiente manera:

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

Una vez que el usuario completa el diálogo proporcionado por startResolutionForResult() o descarta el mensaje proporcionado por GoogleApiAvailability.getErrorDialog(), tu actividad recibe el onActivityResult() con el Código de resultado RESULT_OK. Entonces, tu app podrá llamar connect() de nuevo. Por ejemplo:

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

En el código anterior, es probable que hayas notado el valor booleano, mResolvingError. Esto lleva un registro de la estado de la app mientras el usuario resuelve el error para evitar intentos repetitivos de resolver el mismo . Por ejemplo, mientras se muestra el diálogo del selector de cuenta para ayudar al usuario a resolver el problema SIGN_IN_REQUIRED el usuario puede girar la pantalla. Esto recrea tu actividad y provoca que tu onStart() lo que luego llama connect() de nuevo. Esta genera otra llamada a startResolutionForResult(): lo que creará otro diálogo del selector de cuentas frente al diálogo existente.

Este booleano es válido solo si persiste en todas las instancias de actividad. En la siguiente sección, se explica cómo mantener el estado de manejo de errores de tu app a pesar de otras acciones del usuario o eventos que ocurran en el dispositivo.

Cómo mantener el estado mientras se resuelve un error

Para evitar la ejecución del código en onConnectionFailed() mientras hay en curso un intento anterior de resolver un error, debes conservar un valor booleano que realiza un seguimiento para saber si tu app ya está intentando resolver un error.

Como se muestra en el ejemplo de código anterior, tu app debe establecer un valor booleano en true cada vez que llama startResolutionForResult() o muestra el diálogo de GoogleApiAvailability.getErrorDialog() Luego, cuando tu app reciba RESULT_OK en onActivityResult() establece el valor booleano en false.

Para realizar un seguimiento del valor booleano en los reinicios de la actividad (por ejemplo, cuando el usuario rota la pantalla), guarda el valor booleano en los datos de instancia guardados de la actividad 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);
}

Luego, recupera el estado guardado durante onCreate():

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

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

Ya está todo listo para que ejecutes tu app de forma segura y te conectes manualmente a los Servicios de Google Play.