Integration in das AMAPI SDK

Das AMAPI SDK ermöglicht einer EMM-spezifischen Erweiterungs-App die direkte Kommunikation mit der Android Device Policy. Derzeit unterstützt sie die lokale Ausführung von Commands und nur den Befehl ClearAppData. Für die Integration mit dem SDK sind folgende Schritte erforderlich:

  1. Bibliothek zur Erweiterungs-App hinzufügen
  2. Verwenden Sie die bereitgestellten APIs, um nach Bedarf Befehle auszuführen.
  3. Abfrageelement hinzufügen, wenn das Ziel-SDK größer als 30 ist
  4. Optional können Sie die Implementierung des Dienstes angeben, um Callbacks zur Änderung des Befehlsstatus zu überwachen.
  5. Stellen Sie das Gerät mit der Richtlinie für Erweiterbarkeit bereit.

Voraussetzungen

  • Die minSdkVersion der Erweiterungs-App muss mindestens auf API-Level 21 festgelegt sein.

Bibliothek zur Erweiterungsanwendung hinzufügen

Fügen Sie in der build.gradle-Datei auf oberster Ebene das Google Maven-Repository, das die SDK-Bibliothek enthält, den entsprechenden Modulen hinzu und fügen Sie die Abhängigkeit zur Bibliothek hinzu:

repositories {
  ...
  google()
}

Fügen Sie dann die Bibliothek zum Abhängigkeiten-Block Ihres Moduls hinzu:

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

Anfragen an Android Device Policy senden

Es sollte jetzt möglich sein, Anfragen an ADP zu senden. Die folgenden Anfragen werden unterstützt.

Befehl ausführen

Die Erweiterungs-App kann die Ausführung von Befehlen über ADP anfordern. IssueCommandRequest enthält das Anfrageobjekt mit Details zum auszugebenden Befehl und den spezifischen Parametern. Weitere Informationen dazu finden Sie im Javadoc.

Das folgende Snippet zeigt, wie Sie eine Anfrage zum Löschen der Paketdaten senden:

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

Das obige Beispiel zeigt, wie Sie eine Anfrage für eindeutige Anwendungsdaten für bestimmte Pakete senden und warten, bis der Befehl erfolgreich ausgegeben wurde. Wenn ein Befehlsobjekt erfolgreich ausgegeben wurde, wird es mit dem aktuellen Befehlsstatus und der Befehls-ID zurückgegeben, mit der später der Status von lange laufenden Befehlen abgefragt werden kann.

Befehl abrufen

Die Erweiterungs-App kann auch den Status zuvor ausgegebener Befehlsanfragen abfragen. Zum Abrufen des Status eines Befehls benötigen Sie die Befehls-ID (verfügbar in der Problembefehlsanfrage). Das folgende Snippet zeigt das Senden einer GetCommand-Anfrage an 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());
  }
  ...

Abfrageelement hinzufügen

Wenn Ihre App auf SDK 30 und höher ausgerichtet ist, muss im Manifest durch das Abfrageelement angegeben werden, dass es mit ADP interagieren soll.

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

Weitere Informationen finden Sie unter Filter für die Paketsichtbarkeit unter Android .

Callbacks für Befehlsstatusänderungen überwachen

  1. Änderungen des Befehlsstatus werden an CommandListener gesendet. Implementieren Sie diese Schnittstelle in Ihrer App und geben Sie an, wie die empfangenen Statusaktualisierungen verarbeitet werden sollen.
  2. NotificationReceiverService erweitern und die CommandListener-Instanz bereitstellen.
  3. Geben Sie den Klassennamen des 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
      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. Fügen Sie den Dienst zu Ihrer AndroidManifest.xml-Datei hinzu und vergewissern Sie sich, dass er exportiert wurde.

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

Richtlinienkonfiguration

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

Testen

Unittest

LocalCommandClient ist eine Schnittstelle. Daher können Tests auf einfache Weise eine testbare Implementierung bereitstellen.

Integrationstests

Die folgenden Informationen werden für den Test mit der Android Device Policy benötigt:

  1. Paketname der Erweiterungs-App.
  2. Der hex-codierte SHA-256-Hash der Signatur, die dem Anwendungspaket zugeordnet ist.
  3. Optional beim Testen des Callbacks: vollständig qualifizierter Name des Dienstes aus dem neu eingeführten Dienst zur Unterstützung des Callbacks. Im Beispiel ist der voll qualifizierte Name von CommandService.