Impostare le configurazioni gestite

Se stai sviluppando app per il mercato aziendale, potresti dover soddisfare requisiti particolari impostati dalle norme 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
  • Configurare se un'app è autorizzata a sincronizzare i contenuti tramite rete mobile o solo tramite Wi-Fi
  • Configurare le impostazioni email dell'app

Questa guida mostra come implementare le impostazioni di configurazione gestita nella tua app. Per visualizzare app di esempio con una configurazione gestita, consulta ManagedConfigurations. Se sei uno sviluppatore di soluzioni EMM (Enterprise Mobility Management), 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 effettivamente implementare una vasta gamma di opzioni di configurazione, non solo limitazioni alla funzionalità delle app.

Panoramica della configurazione remota

Le app definiscono le opzioni di configurazione gestita che possono essere impostate da remoto da un amministratore IT. Si tratta di 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 di 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 fornitore di configurazioni gestite. L'app, a sua volta, modifica le configurazioni nella tua app.

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 Google Play.
  • Ogni volta che l'app riprende, utilizza l'oggetto RestrictionsManager per controllare le configurazioni gestite correnti e modificare l'interfaccia utente e il comportamento dell'app in modo che siano conformi a queste configurazioni.
  • Ascolta l'intent ACTION_APPLICATION_RESTRICTIONS_CHANGED. Quando ricevi questo messaggio, controlla RestrictionsManager per vedere quali sono le configurazioni gestite correnti e apporta le modifiche necessarie al comportamento della tua app.

Definire le configurazioni gestite

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

Per definire le opzioni di configurazione remota dell'app, inserisci il seguente elemento nell'elemento <application> del 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 della tua app. La struttura di questo file è descritta nel riferimento per RestrictionsManager. Il file contiene 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 gestito. La tua app può avere un solo file di configurazioni gestite, pertanto le configurazioni saranno coerenti per l'app in tutte le lingue.

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

Il provider di configurazione gestita può eseguire query sull'app per trovare dettagli sulle configurazioni disponibili dell'app, incluso il testo della descrizione. Il fornitore di 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, supponiamo che la tua app possa essere configurata da remoto per consentire o vietare il download di dati tramite una connessione di rete mobile. La tua app potrebbe avere un elemento <restriction> come questo:

<?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>

Utilizza l'attributo android:key di ogni configurazione per leggere il relativo valore da un bundle di configurazione gestito. 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 di stringa.

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

Un'app definisce le restrizioni utilizzando i 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 di limitazione e utilizzo.

Digitazione android:restrictionType Utilizzo tipico
TYPE_BOOLEAN "bool" Un valore booleano, vero o falso.
TYPE_STRING "string" Un valore di 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 di stringa selezionato da android:entryValues, solitamente presentato come un elenco a scelta singola.
TYPE_MULTI_SELECT "multi-select" Un array di stringhe con valori selezionati da android:entryValues. Utilizzalo per presentare un elenco con selezione multipla in cui è possibile selezionare più di una voce, 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 non devono essere presentate all'utente nell'interfaccia utente. Memorizza un singolo valore di stringa.
TYPE_BUNDLE_ARRAY "bundle_array" Utilizzalo per memorizzare array di limitazioni bundles. Disponibile in Android 6.0 (livello API 23).

Nota:i valori android:entryValues sono leggibili dalla macchina e non possono essere localizzati. Utilizza android:entries per presentare valori leggibili che possono essere localizzati. Ogni voce deve avere un indice corrispondente in android:entryValues.

Controllare le configurazioni gestite

La tua app non riceve una notifica automatica quando altre app modificano le sue impostazioni di configurazione. Devi invece controllare quali sono le configurazioni gestite quando l'app si avvia o riprende e ascoltare un intento di sistema per scoprire se le configurazioni cambiano durante l'esecuzione dell'app.

Per scoprire le impostazioni di configurazione correnti, l'app utilizza un oggetto RestrictionsManager. L'app deve controllare le configurazioni gestite correnti nei seguenti momenti:

Per ottenere un oggetto RestrictionsManager, recupera l'attività corrente con getActivity(), quindi chiama il metodo Activity.getSystemService() dell'attività:

Kotlin

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

Java

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

Una volta creato un RestrictionsManager, puoi recuperare le impostazioni di configurazione correnti chiamando il relativo metodo getApplicationRestrictions():

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

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

Il metodo getApplicationRestrictions() richiede la lettura dall'archiviazione dati, pertanto deve essere utilizzato con parsimonia. Non chiamare questo metodo ogni volta che devi conoscere la configurazione corrente. Devi invece chiamarlo una volta all'avvio o al ripristino dell'app e memorizzare nella cache il bundle di configurazioni gestite recuperate. Quindi, ascolta l'intent ACTION_APPLICATION_RESTRICTIONS_CHANGED per scoprire se la configurazione cambia mentre l'app è attiva, come descritto in Rileva le modifiche alla configurazione gestita.

Lettura e applicazione delle 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 impostazioni di configurazione correnti con i metodi Bundle standard per questi tipi di dati, ad esempio getBoolean() o getString().

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

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

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ù restrizioni nidificate, leggi la voce di restrizione bundle_array come una raccolta di oggetti Parcelable e esegui il casting come Bundle. In questo esempio, i dati di configurazione di ogni VPN vengono analizzati e utilizzati per creare un elenco di opzioni 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
}

Ascolta 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. L'app deve ascoltare questo intento per consentirti di modificare il suo comportamento quando cambiano le impostazioni di configurazione.

Nota:l'intent ACTION_APPLICATION_RESTRICTIONS_CHANGED viene inviato solo agli ascoltatori registrati dinamicamente, non a quelli dichiarati nel manifest dell'app.

Il seguente codice mostra come registrare dinamicamente un'entità di ricezione di annunci 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, non è necessario che l'app riceva una notifica relativa alle modifiche alla configurazione quando è in pausa. Devi invece annullare la registrazione del tuo ricevitore di trasmissione quando l'app è in pausa. Quando l'app riprende, controlla innanzitutto le configurazioni gestite correnti (come discusso in Verificare le configurazioni gestite), quindi registra il tuo ricevitore di trasmissione per assicurarti di ricevere una notifica relativa alle modifiche alla configurazione che si verificano quando l'app è attiva.

Inviare feedback sulla configurazione gestita agli EMM

Dopo aver applicato le modifiche alla configurazione gestita alla tua app, è buona prassi informare gli EMM dello stato della modifica. Android supporta una funzionalità chiamata stati dell'app con chiave, che puoi utilizzare per inviare feedback ogni volta che la tua app tenta di applicare modifiche alla configurazione gestita. Questo feedback può fungere da conferma dell'impostazione corretta delle configurazioni gestite o 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 di visualizzarlo nelle loro console per consentirne la visualizzazione agli amministratori IT. Per ulteriori informazioni sull'argomento, consulta Inviare feedback sull'app agli EMM, inclusa una guida dettagliata su come aggiungere il supporto per i feedback alla tua app.

Altri esempi di codice

L'esempio ManagedConfigurations dimostra ulteriormente l'utilizzo delle API trattate in questa pagina.

Inserire app nella lista consentita/nella lista bloccata nel profilo personale

I store di app di terze parti potrebbero esprimere interesse nell'utilizzo delle configurazioni gestite per avere un modo affidabile per applicare una lista consentita o una lista bloccata di app sia al profilo personale sia alla funzionalità consumer Spazio privato, ovvero uno spazio personale aggiuntivo in cui gli utenti possono conservare le app sensibili. Se sviluppi un app store per uso aziendale e vuoi utilizzare questa funzionalità, invia questo modulo per esprimere il tuo interesse e seleziona Interesse per l'inserimento nella lista consentita degli store di terze parti come Motivo della risposta nel modulo.