Apps de extensão e comandos locais

O SDK da API Android Management (AMAPI) permite que um app de extensão especificado pelo EMM se comunicar diretamente com o Android Device Policy (ADP) e executar Commands no dispositivo.

A integração com o SDK da AMAPI fornece mais informações sobre essa biblioteca e como adicioná-la ao aplicativo.

Depois de integrado ao SDK, seu app de extensão pode se comunicar com o ADP para:

Comando de emissão

Um app de extensão pode solicitar que comandos sejam emitidos usando ADP. IssueCommandRequest contém o objeto da solicitação que conterá detalhes sobre o comando a ser emitido e os parâmetros específicos.

O snippet a seguir mostra como emitir uma solicitação para limpar os dados do pacote:

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

O exemplo anterior mostra como emitir uma solicitação clara de dados do app para e aguardar até que o comando seja emitido com sucesso. Se emitido, um objeto Command será retornado com o estado status do comando e o ID do comando que pode ser usado posteriormente para consultar o status do comandos de longa duração.

Receber comando

Um app de extensão pode consultar o status de solicitações de comando emitidas anteriormente. Para recuperar o status de um comando, você precisará do ID de comando (disponível na emitir solicitação de comando). O snippet a seguir mostra como enviar GetCommandRequest para 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());
  }
  ...

Detectar callbacks de alteração de status do comando

Um app de extensão pode registrar um callback para receber atualizações sobre mudanças de status de comandos de longa duração seguindo estas etapas:

  1. As mudanças de status do comando são notificadas para CommandListener. Implemente isso interface em seu aplicativo e fornecer implementação sobre como lidar com o receberam atualizações de status.
  2. Estender NotificationReceiverService e fornecer CommandListener instância.
  3. Especificar o nome da classe do NotificationReceiverService estendido no Android. Política da API Management (consulte a configuração da política).

    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. Adicione o serviço ao AndroidManifest.xml e verifique se ele foi exportado.

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

Configuração da política

Para permitir que o app de extensão se comunique diretamente com o ADP, o EMM precisa fazer o seguinte: forneça uma política extensionConfig.

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

Teste

Teste de unidade

LocalCommandClient é uma interface e, portanto, permite fornecer um objeto testável implementação.

Teste de integração

As seguintes informações são necessárias para testar com o ADP:

  1. Nome do pacote do app da extensão.
  2. O hash SHA-256 da assinatura associada ao app e codificado em hexadecimal .
  3. Opcionalmente, se estiver testando um callback: nome totalmente qualificado do serviço de o serviço recém-lançado para oferecer suporte a callback. (Nome totalmente qualificado do CommandService no exemplo).