Apps de extensiones y comandos locales

El SDK de la API de Android Management (AMAPI) permite que una app de extensión especificada por el EMM se comunique directamente con Android Device Policy (ADP) y ejecute Commands en el dispositivo.

En Integración con el SDK de la AMAPI, se proporciona más información sobre esta biblioteca y cómo agregarla a tu aplicación.

Una vez que se integra el SDK, la app de extensión puede comunicarse con ADP para hacer lo siguiente:

Emitir comando

Una app de extensión puede solicitar que se emitan comandos con ADP. IssueCommandRequest contiene el objeto de solicitud que incluirá detalles sobre el comando que se emitirá y los parámetros específicos.

En el siguiente fragmento, se muestra cómo emitir una solicitud para borrar los datos del paquete:

import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
import com.google.android.managementapi.commands.model.Command;
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest.ClearAppsData;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;

...
  void issueClearAppDataCommand(ImmutableList<String> packageNames) {
    Futures.addCallback(
        LocalCommandClientFactory.create(getContext())
            .issueCommand(createClearAppRequest(packageNames)),
        new FutureCallback<Command>() {
          @Override
          public void onSuccess(Command result) {
            // Process the returned command result here
            Log.i(TAG, "Successfully issued command");
          }

          @Override
          public void onFailure(Throwable t) {
            Log.e(TAG, "Failed to issue command", t);
          }
        },
        MoreExecutors.directExecutor());
  }

  IssueCommandRequest createClearAppRequest(ImmutableList<String> packageNames) {
    return IssueCommandRequest.builder()
        .setClearAppsData(
            ClearAppsData.builder()
                .setPackageNames(packageNames)
                .build()
        )
        .build();
  }
...

En el ejemplo anterior, se muestra cómo emitir una solicitud para borrar los datos de la app para los paquetes especificados y esperar hasta que el comando se haya emitido correctamente. Si se emite correctamente, se devolverá un objeto Command con el estado actual del comando y el ID del comando, que se puede usar más adelante para consultar el estado de cualquier comando de larga duración.

Obtener comando

Una app de extensión puede consultar el estado de las solicitudes de comandos emitidas anteriormente. Para recuperar el estado de un comando, necesitarás el ID del comando (disponible en la solicitud del comando de emisión). En el siguiente fragmento, se muestra cómo enviar un GetCommandRequest al ADP.

import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
...
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;

...
  void getCommand(String commandId) {
    Futures.addCallback(
        LocalCommandClientFactory.create(getApplication())
            .getCommand(GetCommandRequest.builder().setCommandId(commandId).build()),
        new FutureCallback<Command>() {
          @Override
          public void onSuccess(Command result) {
            // Process the returned command result here
            Log.i(Constants.TAG, "Successfully issued command");
          }

          @Override
          public void onFailure(Throwable t) {
            Log.e(Constants.TAG, "Failed to issue command", t);
          }
        },
        MoreExecutors.directExecutor());
  }
  ...

Detecta las devoluciones de llamada de cambio de estado del comando

De manera opcional, una app de extensión puede registrar una devolución de llamada para recibir actualizaciones sobre los cambios de estado de los comandos de ejecución prolongada siguiendo estos pasos:

  1. Los cambios de estado del comando se notifican a CommandListener. Implementa esta interfaz en tu app y proporciona una implementación sobre cómo controlar las actualizaciones de estado recibidas.
  2. Extiende NotificationReceiverService y proporciona una instancia de CommandListener a través del método getCommandListener.
  3. Configura la política de la aplicación para asignarle el rol de COMPANION_APP (consulta Configuración de políticas).

    import com.google.android.managementapi.commands.CommandListener;
    import com.google.android.managementapi.notification.NotificationReceiverService;
    
    ...
    
    public class SampleCommandService extends NotificationReceiverService {
    
     @Override
     public CommandListener getCommandListener() {
       // return the concrete implementation from previous step
       return ...;
     }
    }
    

Configuración de políticas

Para permitir que la app de extensión se comunique directamente con ADP, el EMM debe asignar el rol COMPANION_APP a la app con el campo roles en la política de la aplicación.

 "applications": [{
   "packageName": "com.amapi.extensibility.demo",
   "installType": "FORCE_INSTALLED",
   "roles": [
     { "roleType": "COMPANION_APP" }
   ]
 }]

Para ver las opciones adicionales disponibles, consulta Aprovisiona el dispositivo con políticas de roles de la app.

Prueba

Pruebas de unidades

LocalCommandClient es una interfaz y, por lo tanto, permite proporcionar una implementación que se pueda probar.

Pruebas de integración

Se necesitará la siguiente información para realizar pruebas con ADP:

  1. Es el nombre del paquete de la app de extensión.
  2. Es el hash SHA-256 codificado en base64 de la firma asociada con el paquete de la app.
  3. De forma opcional, si se trata de una devolución de llamada de prueba, es el nombre completamente calificado del servicio del servicio recientemente introducido para admitir la devolución de llamada. (Nombre completamente calificado de CommandService en el ejemplo).