App di estensioni e comandi locali

L'SDK dell'API Android Management (AMAPI) consente a un'app di estensione specificata da EMM di comunicare direttamente con Android Device Policy (ADP) ed eseguire Commands sul dispositivo.

L'articolo Integrare l'SDK AMAPI fornisce ulteriori informazioni su questa libreria e su come aggiungerla alla tua applicazione.

Una volta integrato l'SDK, l'app di estensione può comunicare con ADP per:

Eseguire il comando

Un'app di estensione può richiedere l'esecuzione dei comandi utilizzando ADP. IssueCommandRequest contiene l'oggetto della richiesta che conterrà i dettagli sul comando da eseguire e parametri specifici.

Il seguente snippet mostra come inviare una richiesta per cancellare i dati del pacchetto:

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

L'esempio precedente mostra l'invio di una richiesta di cancellazione dei dati dell'app per i pacchetti specificati e l'attesa fino all'esecuzione corretta del comando. Se l'esecuzione è andata a buon fine, viene restituito un oggetto Command con lo stato attuale del comando e l'ID comando, che può essere utilizzato in un secondo momento per eseguire query sullo stato di eventuali comandi a lunga esecuzione.

Recuperare il comando

Un'app di estensione può eseguire query sullo stato delle richieste di comando eseguite in precedenza. Per recuperare lo stato di un comando, avrai bisogno dell'ID comando (disponibile nella richiesta di esecuzione del comando). Il seguente snippet mostra come inviare un GetCommandRequest ad 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());
  }
  ...

Ascoltare i callback di modifica dello stato del comando

Un'app di estensione può facoltativamente registrare un callback per ricevere aggiornamenti sulle modifiche dello stato dei comandi a lunga esecuzione seguendo questi passaggi:

  1. Le modifiche dello stato del comando vengono notificate a CommandListener. Implementa this interface nella tua app e fornisci l'implementazione su come gestire the received status updates.
  2. Estendi NotificationReceiverService e fornisci un'istanza CommandListener tramite il metodo getCommandListener.
  3. Configura la policy dell'applicazione per assegnare il ruolo COMPANION_APP alla tua app (vedi Configurazione delle policy).

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

Configurazione delle policy

Per consentire all'app di estensione di comunicare direttamente con ADP, l'EMM deve assegnare il ruolo COMPANION_APP all'app utilizzando il campo roles nella policy dell'applicazione.

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

Per ulteriori opzioni disponibili, vedi Provisioning del dispositivo con le policy dei ruoli delle app.

vedi Gestire i ruoli dell'applicazione.

Test

Test delle unità

LocalCommandClient è un'interfaccia e pertanto consente di fornire un'implementazione testabile.

Test di integrazione

Per eseguire i test con ADP, sono necessarie le seguenti informazioni:

  1. Nome del pacchetto dell'app di estensione.
  2. L'hash SHA-256 con codifica Base64 della firma associata al pacchetto dell'app.
  3. (Facoltativo) Se stai testando il callback, il nome completo del servizio dal servizio appena introdotto per supportare il callback. (Nome completo di CommandService nell'esempio).