Impostare le configurazioni gestite

Se sviluppi app per il mercato aziendale, potresti dover soddisfare requisiti specifici stabiliti dai criteri di un'organizzazione. Le configurazioni gestite, precedentemente note come limitazioni delle applicazioni, consentono all'amministratore IT dell'organizzazione di specificare da remoto le impostazioni per le app. Questa funzionalità è particolarmente utile per le app approvate dall'organizzazione di cui è stato eseguito il deployment in un profilo di lavoro.

Ad esempio, un'organizzazione potrebbe richiedere che le app approvate consentano all'amministratore IT di:

  • Consentire o bloccare gli URL per un browser web
  • Configura se un'app può sincronizzare i contenuti tramite rete mobile o solo tramite Wi-Fi
  • Configura le impostazioni email dell'app

Questa guida mostra come implementare le impostazioni di configurazione gestita nella tua app. Per visualizzare le app di esempio con una configurazione gestita, consulta ManagedConfigurations. Se sei uno sviluppatore di gestione della mobilità aziendale (EMM), consulta la guida all'API Android Management.

Nota: per motivi storici, queste impostazioni di configurazione sono note come limitazioni e vengono implementate con file e classi che utilizzano questo termine (ad esempio,RestrictionsManager). Tuttavia, queste limitazioni possono implementare una vasta gamma di opzioni di configurazione, non solo limitazioni relative alla funzionalità dell'app.

Panoramica della configurazione remota

Le app definiscono le opzioni di configurazione gestita che possono essere impostate da remoto da un amministratore IT. Queste sono impostazioni arbitrarie che possono essere modificate da un provider di configurazione gestita. Se la tua app è in esecuzione in un profilo di lavoro, l'amministratore IT può modificare la configurazione gestita dell'app.

Il fornitore delle configurazioni gestite è un'altra app in esecuzione sullo stesso dispositivo. In genere questa app è controllata dall'amministratore IT. L'amministratore IT comunica le modifiche alla configurazione all'app del provider della configurazione gestita, che a sua volta modifica le configurazioni.

Per fornire configurazioni gestite esternamente:

  • Dichiara le configurazioni gestite nel file manifest dell'app. In questo modo l'amministratore IT può leggere le configurazioni dell'app tramite le API di Google Play.
  • Ogni volta che l'app viene ripristinata, utilizza l'oggetto RestrictionsManager per controllare le attuali configurazioni gestite e modifica la UI e il comportamento dell'app per renderli conformi a queste configurazioni.
  • Ascolta l'intent ACTION_APPLICATION_RESTRICTIONS_CHANGED. Quando ricevi questa trasmissione, controlla l'RestrictionsManager per vedere quali sono le attuali configurazioni gestite e apporta le modifiche necessarie al comportamento della tua app.

Definisci le configurazioni gestite

L'app può supportare qualsiasi configurazione gestita che vuoi definire. Dichiari le configurazioni gestite dell'app in un file di configurazioni gestite e il file di configurazione nel manifest. La creazione di un file di configurazione consente ad altre app di esaminare le configurazioni gestite fornite dall'app. I partner EMM possono leggere le configurazioni della tua app utilizzando le API di Google Play.

Per definire le opzioni di configurazione remota dell'app, inserisci il seguente elemento nell'elemento <application> del tuo file manifest:

<meta-data android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />

Crea un file denominato app_restrictions.xml nella directory res/xml dell'app. La struttura di questo file è descritta nel riferimento per RestrictionsManager. Il file ha un singolo elemento <restrictions> di primo livello, che contiene un elemento secondario <restriction> per ogni opzione di configurazione dell'app.

Nota:non creare versioni localizzate del file di configurazione gestita. La tua app può avere un solo file di configurazione gestita, pertanto le configurazioni saranno coerenti per la tua app in tutte le impostazioni internazionali.

In un ambiente aziendale, un EMM utilizza in genere lo schema di configurazione gestita per generare una console remota per gli amministratori IT, in modo che possano configurare la tua applicazione da remoto.

Il provider della configurazione gestita può eseguire query sull'app per trovare i dettagli sulle configurazioni disponibili, incluso il testo descrittivo. Il fornitore delle configurazioni e l'amministratore IT possono modificare le configurazioni gestite della tua app in qualsiasi momento, anche quando l'app non è in esecuzione.

Ad esempio, supponi che la tua app possa essere configurata da remoto per consentire o vietare il download di dati tramite una rete cellulare. La tua app potrebbe avere un elemento <restriction> come il seguente:

<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">

  <restriction
    android:key="downloadOnCellular"
    android:title="@string/download_on_cell_title"
    android:restrictionType="bool"
    android:description="@string/download_on_cell_description"
    android:defaultValue="true" />

</restrictions>

Devi utilizzare l'attributo android:key di ogni configurazione per leggere il relativo valore da un bundle di configurazione gestita. Per questo motivo, ogni configurazione deve avere una stringa di chiave univoca e la stringa non può essere localizzata. Deve essere specificato con un valore letterale stringa.

Nota: in un'app di produzione, android:title e android:description devono essere estratti da un file di risorse localizzato, come descritto in Localizzazione con le risorse.

Un'app definisce le limitazioni utilizzando bundle all'interno di un bundle_array. Ad esempio, un'app con più opzioni di connessione VPN potrebbe definire ogni configurazione del server VPN in un bundle, con più bundle raggruppati in un array di bundle:

<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >

  <restriction
    android:key="vpn_configuration_list"
    android:restrictionType="bundle_array">
    <restriction
      android:key="vpn_configuration"
      android:restrictionType="bundle">
      <restriction
        android:key="vpn_server"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_username"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_password"
        android:restrictionType="string"/>
    </restriction>
  </restriction>

</restrictions>

I tipi supportati per l'elemento android:restrictionType sono elencati nella tabella 1 e documentati nel riferimento per RestrictionsManager e RestrictionEntry.

Tabella 1. Tipi di voci relative alle limitazioni e utilizzo.

Tipo android:restrictionType Utilizzo tipico
TYPE_BOOLEAN "bool" Un valore booleano, true o false.
TYPE_STRING "string" Un valore stringa, ad esempio un nome.
TYPE_INTEGER "integer" Un numero intero con un valore compreso tra MIN_VALUE e MAX_VALUE.
TYPE_CHOICE "choice" Un valore stringa selezionato da android:entryValues, generalmente presentato come un elenco a selezione singola.
TYPE_MULTI_SELECT "multi-select" Un array di stringhe con valori selezionati da android:entryValues. Utilizzalo per presentare un elenco a selezione multipla in cui è possibile selezionare più voci, ad esempio per scegliere titoli specifici da inserire nella lista consentita.
TYPE_NULL "hidden" Tipo di restrizione nascosta. Utilizza questo tipo per le informazioni che devono essere trasferite, ma che non dovrebbero essere presentate all'utente nella UI. Archivia un singolo valore di stringa.
TYPE_BUNDLE_ARRAY "bundle_array" Utilizzalo per archiviare gli array con limitazioni bundles. Disponibile in Android 6.0 (livello API 23).

Nota: i file android:entryValues sono leggibili dalle macchine e non possono essere localizzati. Utilizza android:entries per presentare valori leggibili dall'utente che possono essere localizzati. Ogni voce deve avere un indice corrispondente in android:entryValues.

Controlla le configurazioni gestite

L'app non riceve notifiche automatiche quando altre app modificano le proprie impostazioni di configurazione. Devi invece controllare quali sono le configurazioni gestite quando l'app viene avviata o ripresa e rimanere in ascolto di un intent di sistema per scoprire se le configurazioni cambiano mentre l'app è in esecuzione.

Per scoprire le impostazioni di configurazione attuali, la tua app utilizza un oggetto RestrictionsManager. La tua app deve controllare le attuali configurazioni gestite nei seguenti orari:

Per ottenere un oggetto RestrictionsManager, visualizza l'attività attuale con getActivity(), quindi chiama il metodo Activity.getSystemService() di quell'attività:

Kotlin

var myRestrictionsMgr =
        activity?.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager

Java

RestrictionsManager myRestrictionsMgr =
    (RestrictionsManager) getActivity()
        .getSystemService(Context.RESTRICTIONS_SERVICE);

Una volta che hai un RestrictionsManager, puoi ottenere le impostazioni di configurazione attuali chiamando il relativo metodo getApplicationRestrictions():

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

Nota: per praticità, puoi anche recuperare le configurazioni attuali con un UserManager, chiamando UserManager.getApplicationRestrictions(). Questo metodo si comporta esattamente come RestrictionsManager.getApplicationRestrictions().

Il metodo getApplicationRestrictions() richiede la lettura dall'archiviazione dei dati, quindi va eseguito con parsimonia. Non chiamare questo metodo ogni volta che hai bisogno di conoscere la configurazione attuale. Devi invece chiamarlo una volta quando l'app viene avviata o ripresa e memorizzare nella cache il bundle delle configurazioni gestite recuperate. Quindi ascolta l'intent ACTION_APPLICATION_RESTRICTIONS_CHANGED per scoprire se la configurazione cambia mentre l'app è attiva, come descritto in Ascoltare le modifiche alla configurazione gestita.

Lettura e applicazione di configurazioni gestite

Il metodo getApplicationRestrictions() restituisce un Bundle contenente una coppia chiave-valore per ogni configurazione impostata. I valori sono tutti di tipo Boolean, int, String e String[]. Una volta ottenute le configurazioni gestite Bundle, puoi controllare le attuali impostazioni di configurazione con i metodi Bundle standard per quei tipi di dati, ad esempio getBoolean() o getString().

Nota: le configurazioni gestite Bundle contengono un elemento per ogni configurazione che è stata impostata esplicitamente da un fornitore di configurazioni gestite. Tuttavia, non puoi presupporre che sarà presente una configurazione nel bundle solo perché hai definito un valore predefinito nel file XML delle configurazioni gestite.

Spetta alla tua app intraprendere l'azione appropriata in base alle attuali impostazioni di configurazione gestita. Ad esempio, se la tua app ha una configurazione che specifica se può scaricare i dati tramite una rete cellulare e rilevi che la configurazione è impostata su false, devi disabilitare il download dei dati, tranne quando il dispositivo ha una connessione Wi-Fi, come mostrato nel codice di esempio che segue:

Kotlin

val appCanUseCellular: Boolean =
        if (appRestrictions.containsKey("downloadOnCellular")) {
            appRestrictions.getBoolean("downloadOnCellular")
        } else {
            // cellularDefault is a boolean using the restriction's default value
            cellularDefault
        }

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Java

boolean appCanUseCellular;

if (appRestrictions.containsKey("downloadOnCellular")) {
    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
} else {
    // cellularDefault is a boolean using the restriction's default value
    appCanUseCellular = cellularDefault;
}

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Per applicare più limitazioni nidificate, leggi la voce della limitazione bundle_array come una raccolta di Parcelable oggetti e trasmettila come Bundle. In questo esempio, i dati di configurazione di ogni VPN vengono analizzati e utilizzati per creare un elenco di scelte di connessione al server:

Kotlin

// VpnConfig is a sample class used store config data, not defined
val vpnConfigs = mutableListOf<VpnConfig>()

val parcelables: Array<out Parcelable>? =
        appRestrictions.getParcelableArray("vpn_configuration_list")

if (parcelables?.isNotEmpty() == true) {
    // iterate parcelables and cast as bundle
    parcelables.map { it as Bundle }.forEach { vpnConfigBundle ->
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(VpnConfig()
                .setServer(vpnConfigBundle.getString("vpn_server"))
                .setUsername(vpnConfigBundle.getString("vpn_username"))
                .setPassword(vpnConfigBundle.getString("vpn_password")))
    }
}

if (vpnConfigs.isNotEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

Java

// VpnConfig is a sample class used store config data, not defined
List<VpnConfig> vpnConfigs = new ArrayList<>();

Parcelable[] parcelables =
    appRestrictions.getParcelableArray("vpn_configuration_list");

if (parcelables != null && parcelables.length > 0) {
    // iterate parcelables and cast as bundle
    for (int i = 0; i < parcelables.length; i++) {
        Bundle vpnConfigBundle = (Bundle) parcelables[i];
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(new VpnConfig()
            .setServer(vpnConfigBundle.getString("vpn_server"))
            .setUsername(vpnConfigBundle.getString("vpn_username"))
            .setPassword(vpnConfigBundle.getString("vpn_password")));
    }
}

if (!vpnConfigs.isEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

Attendi le modifiche alla configurazione gestita

Ogni volta che le configurazioni gestite di un'app vengono modificate, il sistema attiva l'intent ACTION_APPLICATION_RESTRICTIONS_CHANGED. La tua app deve rimanere in ascolto di questo intent per consentirti di modificarne il comportamento quando cambiano le impostazioni di configurazione.

Nota: l'intent ACTION_APPLICATION_RESTRICTIONS_CHANGED viene inviato solo ai listener registrati in modo dinamico, non ai listener dichiarati nel file manifest dell'app.

Il codice seguente mostra come registrare dinamicamente un ricevitore di trasmissione per questo intent:

Kotlin

val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED)

val restrictionsReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        // Get the current configuration bundle
        val appRestrictions = myRestrictionsMgr.applicationRestrictions

        // Check current configuration settings, change your app's UI and
        // functionality as necessary.
    }
}

registerReceiver(restrictionsReceiver, restrictionsFilter)

Java

IntentFilter restrictionsFilter =
    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);

BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
  @Override public void onReceive(Context context, Intent intent) {

    // Get the current configuration bundle
    Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

    // Check current configuration settings, change your app's UI and
    // functionality as necessary.
  }
};

registerReceiver(restrictionsReceiver, restrictionsFilter);

Nota: in genere, quando l'app è in pausa non è necessario ricevere notifiche relative alle modifiche alla configurazione. Devi invece annullare la registrazione del ricevitore della trasmissione quando l'app è in pausa. Quando l'app viene ripristinata, innanzitutto controlli le configurazioni gestite attuali (come spiegato nella sezione Controllare le configurazioni gestite), quindi registra il ricevitore della trasmissione per assicurarti di ricevere una notifica relativa alle modifiche alla configurazione che si verificano quando l'app è attiva.

Invia feedback sulla configurazione gestita ai provider EMM

Dopo aver applicato le modifiche alla configurazione gestita all'app, ti consigliamo di comunicare ai provider EMM lo stato della modifica. Android supporta una funzionalità chiamata stati delle app con chiave, che puoi utilizzare per inviare feedback ogni volta che l'app tenta di applicare modifiche alla configurazione gestita. Questo feedback può confermare che le configurazioni gestite dell'app sono state impostate correttamente oppure può includere un messaggio di errore se l'app non è riuscita ad applicare le modifiche specificate.

I provider EMM sono in grado di recuperare questo feedback e visualizzarlo nelle proprie console in modo che gli amministratori IT possano visualizzarlo. Consulta la sezione Inviare feedback sull'app ai provider EMM per ulteriori informazioni sull'argomento, inclusa una guida dettagliata su come aggiungere un feedback di supporto alla tua app.

Altri esempi di codice

L'esempio ManagedConfigurations mostra ulteriormente l'utilizzo delle API illustrate in questa pagina.