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 la Política de dispositivos de Android (ADP) y ejecute Commands en el dispositivo.

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

Una vez que hayas integrado el SDK, tu app de extensión podrá comunicarse con ADP para realizar las siguientes acciones:

Emisión de comandos

Una app de extensión puede solicitar que se emitan comandos con ADP. IssueCommandRequest contiene el objeto de solicitud que contendrá 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 clara de datos de apps para paquetes especificados y esperar hasta que se haya emitido correctamente el comando. Si se emite correctamente, se mostrará un objeto Command con el estado del comando actual y el ID del comando, que se puede usar más adelante para consultar el estado de cualquier comando de larga duración.

Comando Get

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 problema). En el siguiente fragmento, se muestra cómo enviar un GetCommandRequest a 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());
  }
  ...

Escucha 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 de los cambios de estado de los comandos de larga duración siguiendo estos pasos:

  1. Los cambios de estado del comando se notifican a CommandListener, implementan esta interfaz en tu app y proporcionan 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. Especifica el nombre de clase de NotificationReceiverService extendido en la política de la API de Android Management (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 la política

Para permitir que la app de extensión se comunique directamente con ADP, el EMM debe proporcionar una política extensionConfig.

 "applications": [{
   "packageName": "com.amapi.extensibility.demo",
   ...
   "extensionConfig": {
     "signingKeyFingerprintsSha256": [
       // Include signing key of extension app
     ],
     // Optional if callback is implemented
     "notificationReceiver": "com.amapi.extensibility.demo.notification.SampleCommandService"
   }
 }]

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 la prueba con ADP:

  1. Es el nombre del paquete de la app de extensión.
  2. Es el hash SHA-256 con codificación hexadecimal de la firma asociada con el paquete de la app.
  3. De forma opcional, si se prueba la devolución de llamada, el nombre completamente calificado del servicio del servicio recién presentado para admitir la devolución de llamada (nombre completamente calificado de CommandService en el ejemplo).