Erweiterungs-Apps und lokale Befehle

Mit dem AMAPI SDK (Android Management API) kann eine von EMMs angegebene Erweiterungs-App direkt mit Android Device Policy (ADP) kommunizieren und Commands auf dem Gerät ausführen.

Weitere Informationen zu dieser Bibliothek und dazu, wie du sie deiner Anwendung hinzufügen kannst, findest du unter AMAPI SDK einbinden.

Nach der Integration des SDK kann Ihre Erweiterungs-App mit ADP kommunizieren, um:

Befehl ausführen

Eine Erweiterungsanwendung kann anfordern, dass Befehle über ADP erteilt werden. IssueCommandRequest enthält das Anfrageobjekt mit Details zum auszugebenden Befehl und spezifischen Parametern.

Im folgenden Snippet wird gezeigt, wie eine Anfrage zum Löschen der Daten des Pakets gesendet wird:

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

Im vorherigen Beispiel wird eine Anfrage zum Löschen von App-Daten für bestimmte Pakete gesendet und darauf gewartet, bis der Befehl erfolgreich ausgeführt wurde. Bei Erfolg wird ein Command-Objekt mit dem aktuellen Befehlsstatus und der Befehls-ID zurückgegeben. Mit dieser ID kann später der Status aller Befehle mit langer Ausführungszeit abgefragt werden.

Befehl abrufen

Eine Erweiterungs-App kann den Status zuvor gesendeter Befehlsanfragen abfragen. Um den Status eines Befehls abzurufen, benötigen Sie die Befehls-ID, die in der Anfrage zum Ausführen des Befehls enthalten ist. Im folgenden Snippet wird gezeigt, wie ein GetCommandRequest an ADP gesendet wird.

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

Callbacks für Statusänderungen von Befehlen empfangen

Eine Erweiterungs-App kann optional einen Rückruf registrieren, um Updates für Statusänderungen von lang laufenden Befehlen zu erhalten. Gehen Sie dazu so vor:

  1. Änderungen am Befehlsstatus werden an CommandListener gesendet. Implementieren Sie diese Schnittstelle in Ihrer App und geben Sie an, wie mit den empfangenen Statusaktualisierungen umgegangen werden soll.
  2. Erweitern Sie NotificationReceiverService und geben Sie über die Methode getCommandListener eine CommandListener-Instanz an.
  3. Geben Sie den Klassennamen der erweiterten NotificationReceiverService in der Android Management API-Richtlinie an (siehe Richtlinienkonfiguration).

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

Richtlinienkonfiguration

Damit die Erweiterungs-App direkt mit ADP kommunizieren kann, muss der EMM eine extensionConfig-Richtlinie bereitstellen.

 "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

Unittest

LocalCommandClient ist eine Schnittstelle und ermöglicht so eine testbare Implementierung.

Integrationstests

Für den Test mit ADP sind die folgenden Informationen erforderlich:

  1. Paketname der Erweiterungs-App.
  2. Der hexadezimal codierte SHA-256-Hash der Signatur, die mit dem App-Paket verknüpft ist.
  3. Optional, wenn Callback getestet wird: Vollständig qualifizierter Name des Dienstes aus dem neu eingeführten Dienst, der Callback unterstützt. (Vollständig qualifizierter Name von CommandService im Beispiel)