Llamar a APIs de backend desde un cliente Android

En esta página se describe cómo llama un cliente Android a una API de backend creada con Cloud Endpoints Frameworks para App Engine.

Generar la biblioteca de cliente

Tu cliente Android requiere la biblioteca de cliente generada a partir de la API de backend que esté usando. Si aún no tienes la biblioteca de cliente, consulta la sección Generar una biblioteca de cliente para obtener más información. En este documento se explica cómo añadir la biblioteca de cliente al proyecto de cliente de Android.

Configurar el proyecto

En estas instrucciones, se usa Android Studio. Si aún no lo has hecho, debes configurar Android Studio para que admita un cliente que use los frameworks.

Configurar el proyecto

En Android Studio, tu proyecto usa el archivo build.gradle para las dependencias y otros ajustes. De forma predeterminada, Android Studio crea un archivo build.gradle a nivel de proyecto principal y otro específico de la aplicación Android en el módulo Android. Estas instrucciones son para el build.gradle específico de la aplicación en el módulo de Android.

Para configurar build.gradle, sigue estos pasos:

  1. Haz doble clic en build.gradle para abrirlo.

  2. Edita este archivo para que contenga las siguientes líneas:

    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:1.0.0'
        }
    }
    apply plugin: 'com.android.application'
    
    repositories {
        mavenCentral()
        mavenLocal()
    }
    
    android {
        compileSdkVersion 26
    
        defaultConfig {
            applicationId "com.mycompany.myapp"
            minSdkVersion 17
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        packagingOptions {
            exclude 'META-INF/DEPENDENCIES'
        }
    }
    
    dependencies {
        implementation 'com.android.support:appcompat-v7:26.1.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        // BEGIN Google APIs
        // Play Services will validate the application prior to allowing OAuth2 access.
        implementation 'com.google.android.gms:play-services-auth:16.0.0'
        implementation 'com.google.android.gms:play-services-identity:16.0.0'
        // The following lines implement maven imports as defined at:
        // https://github.com/googleapis/google-api-java-client/wiki/Setup-Instructions
        // Add the Google API client library.
        implementation('com.google.api-client:google-api-client:1.28.0') {
            // Exclude artifacts that the Android SDK/Runtime provides.
            exclude(group: 'xpp3', module: 'xpp3')
            exclude(group: 'org.apache.httpcomponents', module: 'httpclient')
            exclude(group: 'junit', module: 'junit')
            exclude(group: 'com.google.android', module: 'android')
        }
        // Add the Android extensions for the Google API client library.
        // This will automatically include play services as long as you have download that library
        // from the Android SDK manager.
        // Add the Android extensions for the Google API client library.
        implementation(group: 'com.google.api-client', name: 'google-api-client-android', version: '1.25.0') {
                   // Exclude play services, since we're not using this yet.
                  exclude(group: 'com.google.android.gms:play-services', module: 'google-play-services')
        }
        // END Google APIs
        // The following client libraries make HTTP/JSON on Android easier.
        // Android extensions for Google HTTP Client.
        implementation('com.google.http-client:google-http-client-android:1.21.0') {
            exclude(group: 'com.google.android', module: 'android')
        }
        implementation 'com.google.http-client:google-http-client-gson:1.21.0'
        // This is used by the Google HTTP client library.
        implementation 'com.google.guava:guava:18.0+'
        implementation files('libs/echo-v1-1.25.0-SNAPSHOT.jar')
    }
    
    

    Sustituye com.mycompany.myapp por tus propios valores.

  3. Haz clic en File (Archivo) > Save All (Guardar todo). Después, cierra Android Studio y vuelve a abrirlo.

Añadir la biblioteca de cliente al proyecto

Para añadir la biblioteca de cliente al proyecto de Android, sigue estos pasos:

  1. Añade un directorio /libs a tu proyecto si aún no tiene uno. Es un directorio de /src.

  2. Copia la biblioteca de cliente generada a partir de la API de backend en /libs.

  3. Haz clic con el botón derecho en la biblioteca que acabas de añadir y, a continuación, selecciona Añadir como biblioteca a tu proyecto.

Crear el objeto de servicio

En el código de tu proyecto, debes usar un objeto de servicio para hacer solicitudes a la API backend. En el caso de las solicitudes sin autenticar, crea el objeto de servicio de la siguiente manera:

BACKEND_API_NAME.Builder builder = new BACKEND_API_NAME.Builder(
    NetHttpTransport(), new GsonFactory(), null);
service = builder.build();

Sustituye BACKEND_API_NAME por el nombre de tu API backend.

Llamar a la API backend

En tu proyecto, llama a la API mediante el objeto de servicio. Por ejemplo:

ScoreCollection scores = service.scores().list().execute();

En este fragmento, se solicita una lista de todos los objetos Score del servidor. Si list requiere parámetros o un cuerpo de solicitud, debes proporcionarlos en el comando. Android Studio ofrece la función de autocompletar código para identificar las llamadas de métodos disponibles y sus parámetros obligatorios.

Es importante tener en cuenta que, como las llamadas a la API dan lugar a solicitudes a través de la red, debes hacer las solicitudes en su propio subproceso. Este requisito se añadió a las versiones recientes de Android, pero es una práctica recomendada incluso en versiones anteriores. Para ello, puedes usar un Thread o un AsyncTask. Por ejemplo:

private class QueryScoresTask extends AsyncTask<Void, Void, ScoreCollection>{
  Context context;

  public QueryScoresTask(Context context) {
    this.context = context;
  }

  protected Scores doInBackground(Void... unused) {
    ScoreCollection scores = null;
    try {
      scores = service.scores().list().execute();
    } catch (IOException e) {
      Log.d("TicTacToe", e.getMessage(), e);
    }
    return scores;
  }

  protected void onPostExecute(ScoreCollection scores) {
    // Do something with the result.
  }
}

Hacer llamadas autenticadas

Estas instrucciones solo abarcan la codificación de cliente que debes añadir. Se presupone que ya has añadido la compatibilidad con Endpoints Frameworks para la autenticación, tal como se describe en Autenticar usuarios.

Si tu cliente Android hace llamadas a un endpoint que requiere autenticación, debes hacer lo siguiente:

  • Configura tu cliente Android para que proporcione las credenciales al objeto de servicio.
  • Usa el selector de cuentas para permitir que los usuarios elijan con qué cuenta quieren iniciar sesión.

En las siguientes secciones se proporcionan más detalles al respecto.

Configurar el cliente Android para que proporcione credenciales

Para admitir solicitudes a una API de backend que requiera autenticación, tu cliente Android debe obtener las credenciales de usuario y pasarlas al objeto de servicio.

Para obtener las credenciales del usuario y usar el selector de cuentas, debes tener los siguientes permisos de Android:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

Para obtener las credenciales del usuario, llama a GoogleAccountCredential.usingAudience de la siguiente manera:

// Inside your Activity class onCreate method
settings = getSharedPreferences(
    "TicTacToeSample", 0);
credential = GoogleAccountCredential.usingAudience(this,
    "server:client_id:1-web-app.apps.googleusercontent.com");

El segundo parámetro de la llamada es el prefijo server:client_id que se añade al ID de cliente web de la API backend.

Código de ejemplo: obtener las credenciales del objeto de servicio

En el siguiente código se muestra cómo obtener las credenciales y pasarlas al objeto de servicio:

// Inside your Activity class onCreate method
settings = getSharedPreferences("TicTacToeSample", 0);
credential = GoogleAccountCredential.usingAudience(this,
    "server:client_id:1-web-app.apps.googleusercontent.com");
setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));

Tictactoe.Builder builder = new Tictactoe.Builder(
    NetHttpTransport(), new GsonFactory(),
    credential);
service = builder.build();

if (credential.getSelectedAccountName() != null) {
  // Already signed in, begin app!
} else {
  // Not signed in, show login window or request an account.
}

// setSelectedAccountName definition
private void setSelectedAccountName(String accountName) {
  SharedPreferences.Editor editor = settings.edit();
  editor.putString(PREF_ACCOUNT_NAME, accountName);
  editor.commit();
  credential.setSelectedAccountName(accountName);
  this.accountName = accountName;
}

El código de ejemplo anterior busca las preferencias compartidas almacenadas por la aplicación Android e intenta encontrar el nombre de la cuenta que el usuario quiere usar para autenticarse en tu aplicación. Si se ejecuta correctamente, el código crea un objeto de credenciales y lo pasa al objeto de servicio. Estas credenciales permiten que tu aplicación Android transfiera el token adecuado a tu backend.

Ten en cuenta que el código de ejemplo comprueba si la aplicación Android ya sabe qué cuenta debe usar. Si es así, el flujo lógico puede continuar y ejecutar la aplicación Android. Si la aplicación no sabe qué cuenta usar, muestra una pantalla de inicio de sesión o pide al usuario que elija una cuenta.

Por último, el ejemplo crea un objeto de credenciales y lo pasa al objeto de servicio. Estas credenciales permiten que tu aplicación Android envíe el token adecuado a tu aplicación web de App Engine.

Usar el selector de cuentas

Android proporciona un intent para seleccionar una cuenta de usuario. Puedes invocarlo de la siguiente manera:

static final int REQUEST_ACCOUNT_PICKER = 2;

void chooseAccount() {
  startActivityForResult(credential.newChooseAccountIntent(),
      REQUEST_ACCOUNT_PICKER);
}

Aquí se muestra un controlador para interpretar el resultado de esta intención:

@Override
protected void onActivityResult(int requestCode, int resultCode,
   Intent data) {
 super.onActivityResult(requestCode, resultCode, data);
 switch (requestCode) {
   case REQUEST_ACCOUNT_PICKER:
     if (data != null && data.getExtras() != null) {
       String accountName =
           data.getExtras().getString(
               AccountManager.KEY_ACCOUNT_NAME);
       if (accountName != null) {
         setSelectedAccountName(accountName);
         SharedPreferences.Editor editor = settings.edit();
         editor.putString(PREF_ACCOUNT_NAME, accountName);
         editor.commit();
         // User is authorized.
       }
     }
     break;
  }
}

Probar un cliente Android con un servidor de desarrollo local

Puedes probar tu cliente con una API de backend que se ejecute en la producción de App Engine en cualquier momento sin hacer ningún cambio. Sin embargo, si quieres probar tu cliente con una API de backend que se ejecute en el servidor de desarrollo local, debes cambiar la línea de código del cliente para que apunte a la dirección IP de la máquina que ejecuta el servidor de desarrollo local.

Para hacer los cambios necesarios y probarlos con el servidor de desarrollo local, sigue estos pasos:

  1. Anota la dirección IP del ordenador que ejecuta el servidor de desarrollo local, ya que la necesitarás cuando añadas código al cliente Android.

  2. Inicia el servidor de desarrollo local, tal como se describe en Probar una API de forma local.

  3. En tu proyecto de cliente de Android Studio, busca el código que obtiene el controlador del servicio de la API de backend. Normalmente, este código usa un Builder para configurar la solicitud de la API.

  4. Para anular la URL raíz en el objeto Builder (es la URL a la que se conecta el cliente de Android en la llamada a la API backend), añade la siguiente línea:

    yourBuilderObject.setRootUrl("http://YOUR_MACHINE_IP_ADDRESS:8080/_ah/api");
    

    Por ejemplo:

    public static Helloworld getApiServiceHandle(@Nullable GoogleAccountCredential credential) {
      // Use a builder to help formulate the API request.
      Helloworld.Builder helloWorld = new Helloworld.Builder(AppConstants.HTTP_TRANSPORT,
          AppConstants.JSON_FACTORY,credential);
    
      helloWorld.setRootUrl("http://YOUR_MACHINE_IP_ADDRESS:8080/_ah/api");
      return helloWorld.build();
    }
    

    Sustituye YOUR_MACHINE_IP_ADDRESS por la dirección IP de tu sistema.

  5. Recompila tu proyecto de cliente Android.

  6. Si quieres ejecutar tu aplicación cliente en un emulador de AVD, sigue estos pasos:

    1. En Android Studio, ve a Tools (Herramientas) > Android > AVD Manager (Gestor de AVDs) y inicia un AVD si ya tienes uno. De lo contrario, crea uno y luego inícialo.
    2. Ve a Ejecutar > Depurar YOUR_PROJECT_NAME donde YOUR_PROJECT_NAME representa el nombre de tu proyecto Google Cloud .
    3. Cuando se te pida que elijas un dispositivo, selecciona tu AVD.
    4. Prueba tu cliente.
  7. Si quieres ejecutar tu aplicación cliente en un dispositivo Android físico, sigue estos pasos:

    1. Comprueba que la depuración esté habilitada en tu dispositivo Android.
    2. En Android Studio, ve a Ejecutar > Depurar YOUR_PROJECT_NAME.
    3. Cuando se te pida que elijas un dispositivo, selecciona tu dispositivo Android físico.
    4. Prueba tu cliente.

Código fuente de cliente de ejemplo

Para ver un código de muestra, consulta el ejemplo de Android Cloud Endpoints v2.0.