Intégration au SDK AMAPI

Le SDK AMAPI permet à une application d'extension spécifiée par EMM de communiquer directement avec Android Device Policy. Actuellement, elle est compatible avec l'exécution locale de Commands, et uniquement la commande ClearAppData. Pour intégrer le SDK, procédez comme suit:

  1. Ajouter une bibliothèque à l'application d'extension
  2. Utilisez les API fournies pour émettre des commandes si nécessaire.
  3. Ajoutez l'élément de requêtes si le SDK cible est supérieur ou égal à 30.
  4. Vous pouvez éventuellement fournir une implémentation de service pour écouter les rappels de changement d'état de la commande.
  5. Provisionner l'appareil à l'aide des règles d'extensibilité

Conditions préalables

  • Assurez-vous que la valeur minSdkVersion de l'application d'extension est définie au moins sur le niveau d'API 21.

Ajouter une bibliothèque à l'application de l'extension

Dans le fichier build.gradle de premier niveau, ajoutez le dépôt Maven de Google qui contient la bibliothèque SDK aux modules concernés et ajoutez la dépendance à la bibliothèque:

repositories {
  ...
  google()
}

Ajoutez ensuite la bibliothèque au bloc de dépendances de votre module:

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

Envoyer des demandes à Android Device Policy

Il devrait maintenant être possible d'envoyer des requêtes à ADP. Les requêtes suivantes sont acceptées.

Émettre une commande

L'application d'extension peut demander l'émission de commandes via ADP. IssueCommandRequest contient l'objet de requête qui comprend des détails sur la commande à émettre et des paramètres spécifiques. Pour en savoir plus, consultez Javadoc.

L'extrait de code suivant montre comment envoyer une demande de suppression des données du package:

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'exemple ci-dessus montre comment émettre une requête de données d'application claire pour les packages spécifiés et attendre que la commande a été correctement émise. Si l'exécution aboutit, un objet Command est renvoyé avec l'état actuel de la commande et l'ID de commande, qui peut ensuite être utilisé pour interroger l'état de toutes les commandes de longue durée.

Obtenir la commande

L'application d'extension peut également interroger l'état des requêtes de commande précédemment émises. Pour récupérer l'état d'une commande, vous aurez besoin de l'ID de la commande (disponible dans la requête de commande d'erreur). L'extrait de code suivant montre comment envoyer une requête GetCommand à 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());
  }
  ...

Ajout de l'élément de requêtes

Si votre application cible le SDK 30 ou une version ultérieure, l'élément de requête est nécessaire dans le fichier manifeste pour spécifier qu'il interagira avec ADP.

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

Pour en savoir plus, consultez la section Filtrer la visibilité des packages sur Android .

Écouter les rappels de changement d'état des commandes

  1. Les changements d'état des commandes sont notifiés au CommandListener, implémentez cette interface dans votre application et indiquez comment gérer les mises à jour d'état reçues.
  2. Étendre NotificationReceiverService et fournir une instance CommandListener.
  3. Spécifiez le nom de classe de NotificationReceiverService étendu dans la règle de l'API Android Management (voir "Configuration des règles").

    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. Ajoutez le service à votre fichier AndroidManifest.xml et assurez-vous qu'il est exporté.

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

Configuration des règles

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

Tests

Tests unitaires

LocalCommandClient est une interface. Les tests permettent donc de fournir facilement une implémentation testable.

Tests d'intégration

Les informations suivantes sont nécessaires pour tester Android Device Policy:

  1. Nom de package de l'application de l'extension.
  2. Hachage SHA-256 de la signature associée au package de l'application, encodé en hexadécimal.
  3. Éventuellement, si vous testez le rappel : nom complet du service provenant du nouveau service pour permettre le rappel. (Nom complet de CommandService dans l'exemple).