Integrazione con l'SDK AMAPI

L'SDK AMAPI consente a un'app di estensione specificata con EMM di comunicare direttamente con Android Device Policy. Attualmente include il supporto per l'esecuzione locale di Commands e solo per il comando ClearAppData. Per l'integrazione con l'SDK è necessario eseguire i seguenti passaggi:

  1. Aggiungi la raccolta all'app dell'estensione.
  2. Utilizza le API fornite per inviare comandi secondo necessità.
  3. Aggiungi elemento query, se SDK target >= 30.
  4. Facoltativamente, puoi fornire l'implementazione del servizio per ascoltare i callback di modifica dello stato dei comandi.
  5. Esegui il provisioning del dispositivo con un criterio di estensibilità.

Prerequisiti

  • Assicurati che il valore minSdkVersion dell'app dell'estensione sia impostato almeno sul livello API 21.

Aggiunta di una libreria all'applicazione di estensione

Nel file build.gradle di primo livello, aggiungi il Repository Maven di Google che contiene la libreria SDK ai moduli pertinenti e aggiungi la dipendenza alla libreria:

repositories {
  ...
  google()
}

Quindi, aggiungi la libreria al blocco delle dipendenze del modulo:

dependencies {
  implementation 'com.google.android.libraries.enterprise.amapi:amapi:1.0.0'
}

Invia richieste ad Android Device Policy

Ora dovrebbe essere possibile inviare richieste ad ADP. Sono supportate le seguenti richieste.

Esegui comando

L'app dell'estensione può richiedere comandi da inviare tramite ADP. IssueCommandRequest contiene l'oggetto della richiesta che conterrà i dettagli sul comando da emettere e i parametri specifici. Ulteriori informazioni sono disponibili nel Javadoc.

Lo snippet seguente mostra come inviare una richiesta di cancellazione dei 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 dati dell'app chiara per i pacchetti specificati e l'attesa che il comando venga emesso correttamente. Se viene eseguito correttamente, un oggetto Command verrà restituito con lo stato attuale del comando e l'ID comando, che potrà essere successivamente utilizzato per eseguire query sullo stato di eventuali comandi a lunga esecuzione.

Ottieni comando

L'app dell'estensione può anche eseguire query sullo stato delle richieste di comando inviate in precedenza. Per recuperare lo stato di un comando, avrai bisogno dell'ID comando (disponibile nella richiesta del comando di emissione). Lo snippet seguente mostra l'invio di una richiesta GetCommand 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());
  }
  ...

Aggiunta di elementi di query

Se la tua app ha come target l'SDK 30 e versioni successive, nel file manifest è necessario l'elemento di query per specificare che interagirà con ADP.

<queries>
    <package android:name="com.google.android.apps.work.clouddpc" />
</queries>

Per ulteriori informazioni, consulta Filtro della visibilità dei pacchetti su Android .

Ascolta i callback di modifica dello stato dei comandi

  1. Le modifiche allo stato del comando vengono inviate a CommandListener, implementa questa interfaccia nell'app e fornisci l'implementazione su come gestire gli aggiornamenti dello stato ricevuti.
  2. Extend NotificationRicevirService e fornisci un'istanza CommandListener.
  3. Specifica il nome della classe di NotificationRicevirService estesa nel criterio dell'API Android Management (vedi Configurazione dei criteri).

    import com.google.android.managementapi.commands.CommandListener;
    import com.google.android.managementapi.notification.NotificationReceiverService;
    
    ...
    
    public class SampleCommandService extends NotificationReceiverService {
    
      @Override
      protected void setupInjection() {
        // (Optional) If using DI and needs initialisation then use this method.
      }
    
      @Override
      public CommandListener getCommandListener() {
        // return the concrete implementation from previous step
        return ...;
      }
    }
    
  4. Aggiungi il servizio al file AndroidManifest.xml e assicurati che venga esportato.

    <service
     android:name = ".notification.SampleCommandService"
     android:exported = "true" />
    

Configurazione dei criteri

 "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"
   }
 }]

Test

Test delle unità

LocalCommandClient è un'interfaccia e quindi il test consente di fornire facilmente un'implementazione testabile.

Test di integrazione

Per eseguire il test con Android Device Policy saranno necessarie le seguenti informazioni:

  1. Nome del pacchetto dell'app dell'estensione.
  2. L'hash SHA-256 con codifica esadecimale della firma associata al pacchetto dell'app.
  3. Facoltativamente, in caso di test del callback, il nome completo del servizio del servizio appena introdotto per supportare il callback. (nome completo di CommandService nell'esempio).