L'SDK dell'API Android Management (AMAPI) consente a un'app di estensione specificata dall'EMM di comunicare direttamente con Android Device Policy (ADP) ed eseguire Commands sul dispositivo.
Integra con l'SDK AMAPI fornisce ulteriori informazioni su questa libreria e su come aggiungerla alla tua applicazione.
Una volta integrato l'SDK, l'app di estensione può comunicare con ADP per:
- Inviare richieste di comando
- eseguire query sullo stato delle richieste di comando
- ricevere modifiche allo stato dei comandi
Esegui comando
Un'app di estensione può richiedere l'invio di comandi tramite ADP.
IssueCommandRequest contiene l'oggetto della richiesta che conterrà i dettagli sul comando da inviare e i parametri specifici.
Cancellare i dati delle app
Il seguente snippet mostra come inviare una richiesta per cancellare i 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 cancellazione dei dati dell'app per i pacchetti specificati e l'attesa fino all'invio del comando. Se
l'emissione va a buon fine, verrà restituito un oggetto Command con lo stato
del comando corrente e l'ID comando che può essere utilizzato in un secondo momento per eseguire query sullo stato di
qualsiasi comando a lunga esecuzione.
Cancellare i dati dal dispositivo o dal profilo di lavoro
Un'app complementare può inviare un comando Wipe locale quando l'amministratore IT assegna
il ruolo COMPANION_APP con la funzionalità aggiuntiva
LOCAL_DEVICE_WIPE_COMMAND_ALLOWED. Sui dispositivi di proprietà dell'azienda, questa operazione ripristina i dati di fabbrica del dispositivo; sui dispositivi di proprietà personale con un profilo di lavoro, rimuove il profilo di lavoro. Se l'app non dispone di questo ruolo e di questa funzionalità aggiuntiva, la richiesta non va a buon fine. Per i dettagli, consulta Configurazione delle policy.
Entrambi i parametri Wipe sono facoltativi. Se non vuoi specificare un valore, ometti il setter del builder o passa una raccolta vuota o una stringa vuota (non passare null).
- I valori
WipeDataFlagcontrollano quali dati vengono cancellati:PRESERVE_RESET_PROTECTION_DATA: conserva i dati della protezione del ripristino dei dati di fabbrica, che vengono cancellati per impostazione predefinita. Si applica solo ai dispositivi di proprietà dell'azienda.WIPE_EXTERNAL_STORAGE: cancella anche lo spazio di archiviazione esterno, ad esempio le schede SD. Si applica solo ai dispositivi di proprietà dell'azienda.WIPE_ESIMS: rimuove tutte le eSIM dai dispositivi di proprietà aziendale. Sui dispositivi di proprietà personale, rimuove solo le eSIM gestite (su Android 16 o versioni successive, le eSIM gestite vengono sempre rimosse con il profilo di lavoro, indipendentemente dal fatto che questo flag sia impostato o meno).
wipeReason: un breve messaggio, di massimo 200 caratteri, che viene mostrato all'utente quando il profilo di lavoro viene rimosso da un dispositivo di proprietà personale. Non ha alcun effetto sui dispositivi di proprietà dell'azienda.
Il seguente snippet mostra come inviare una richiesta di cancellazione del dispositivo o del profilo di lavoro:
Kotlin
import android.content.Context
import android.util.Log
...
import com.google.android.managementapi.commands.CommandException
import com.google.android.managementapi.commands.LocalCommandClientFactory
import com.google.android.managementapi.commands.model.IssueCommandRequest
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe.WipeDataFlag
...
suspend fun issueWipeCommand(
context: Context,
wipeDataFlags: List<WipeDataFlag>,
wipeReason: String,
) {
try {
val command =
LocalCommandClientFactory.create(context)
.issueCommandAwait(createWipeRequest(wipeDataFlags, wipeReason))
Log.i(TAG, "Successfully issued wipe command: ${command.commandId}")
} catch (e: CommandException) {
Log.e(TAG, "Failed to issue wipe command", e)
}
}
fun createWipeRequest(
wipeDataFlags: List<WipeDataFlag>,
wipeReason: String,
): IssueCommandRequest =
IssueCommandRequest.builder()
.setWipe(
Wipe.builder()
.setWipeDataFlags(wipeDataFlags)
.setWipeReason(wipeReason)
.build()
)
.build()
...
Java
import android.content.Context;
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.IssueCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe;
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe.WipeDataFlag;
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 issueWipeCommand(
Context context,
ImmutableList<WipeDataFlag> wipeDataFlags,
String wipeReason) {
Futures.addCallback(
LocalCommandClientFactory.create(context)
.issueCommand(createWipeRequest(wipeDataFlags, wipeReason)),
new FutureCallback<Command>() {
@Override
public void onSuccess(Command result) {
Log.i(TAG, "Successfully issued wipe command: " + result.getCommandId());
}
@Override
public void onFailure(Throwable t) {
Log.e(TAG, "Failed to issue wipe command", t);
}
},
MoreExecutors.directExecutor());
}
IssueCommandRequest createWipeRequest(
ImmutableList<WipeDataFlag> wipeDataFlags, String wipeReason) {
return IssueCommandRequest.builder()
.setWipe(
Wipe.builder()
.setWipeDataFlags(wipeDataFlags)
.setWipeReason(wipeReason)
.build())
.build();
}
...
Ottieni comando
Un'app di estensione può eseguire query sullo stato delle richieste di comando inviate in precedenza. Per recuperare lo stato di un comando, devi disporre dell'ID comando (disponibile nella richiesta di emissione del comando). Il seguente snippet mostra come inviare un
GetCommandRequest 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());
}
...
Ascolta i callback di modifica dello stato dei comandi
Un'app di estensione può facoltativamente registrare un callback per ricevere aggiornamenti per le modifiche di stato dei comandi a lunga esecuzione seguendo questi passaggi:
- Le modifiche allo stato dei comandi vengono notificate a
CommandListener. Implementa questa interfaccia nella tua app e fornisci l'implementazione su come gestire gli aggiornamenti di stato ricevuti. - Estendi
NotificationReceiverServicee fornisci un'istanzaCommandListenertramite il metodogetCommandListener. Configura la policy dell'applicazione per assegnare il ruolo
COMPANION_APPalla tua app (vedi Configurazione della policy).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 ...; } }
Configurazione delle policy
Per consentire all'app complementare di comunicare direttamente con ADP, l'EMM deve assegnare il ruolo COMPANION_APP all'app utilizzando il campo roles nella policy dell'applicazione:
"applications": [{
"packageName": "com.amapi.extensibility.demo",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "COMPANION_APP" }
]
}]
Per consentire all'app complementare di inviare un comando Wipe locale, imposta
extraCapabilities.localDeviceWipeCommand su
LOCAL_DEVICE_WIPE_COMMAND_ALLOWED:
"applications": [{
"packageName": "com.amapi.extensibility.demo",
"installType": "FORCE_INSTALLED",
"roles": [
{
"roleType": "COMPANION_APP",
"extraCapabilities": {
"localDeviceWipeCommand": "LOCAL_DEVICE_WIPE_COMMAND_ALLOWED"
}
}
]
}]
Per altre opzioni disponibili, consulta Esegui il provisioning del dispositivo con le policy dei ruoli delle app.
Il servizio che ascolta le modifiche dello stato dei comandi viene rilevato automaticamente da ADP utilizzando i metadati nel manifest dell'app e non deve più essere specificato nella policy come notificationReceiver. Per maggiori dettagli su come preparare l'app e il manifest, consulta Gestisci i ruoli dell'applicazione.
Test
Test delle unità
LocalCommandClient è un'interfaccia e pertanto consente di fornire un'implementazione testabile.
Test di integrazione
Per eseguire i test con ADP, saranno necessarie le seguenti informazioni:
- Nome del pacchetto dell'app di estensione.
- L'hash SHA-256 con codifica base64 della firma associata al pacchetto dell'app.
- Facoltativamente, se stai testando il callback, il nome completo del servizio appena introdotto per supportare il callback. (Nome completo di
CommandServicenell'esempio).