Cómo establecer opciones de configuración administradas

Si desarrollas apps para el mercado empresarial, es posible que debas satisfacer requisitos específicos establecidos por las políticas de una organización. Las opciones de configuración administradas, antes conocidas como restricciones de las aplicaciones, permiten que el administrador de TI de la organización especifique de forma remota la configuración de las apps. Esta capacidad es particularmente útil para las apps aprobadas por organizaciones que se implementan en un perfil de trabajo.

Por ejemplo, una organización podría requerir que las apps aprobadas permitan al administrador de TI hacer lo siguiente:

  • Cómo permitir o bloquear URLs para un navegador web
  • Configura si una app puede sincronizar contenido a través de la red móvil o solo por Wi-Fi.
  • Configura la configuración de correo electrónico de la app

En esta guía, se muestra cómo implementar la configuración de configuración administrada en tu app. Para ver apps de ejemplo con una configuración administrada, consulta ManagedConfigurations. Si eres desarrollador de administración de movilidad empresarial (EMM), consulta la guía de la API de Android Management.

Nota: Por razones históricas, estos parámetros de configuración se conocen como restricciones y se implementan con archivos y clases que usan este término (como RestrictionsManager). Sin embargo, estas restricciones pueden implementar una amplia variedad de opciones de configuración, no solo restricciones en la funcionalidad de la app.

Descripción general de la configuración remota

Las apps definen las opciones de configuración administradas que un administrador de TI puede establecer de forma remota. Estos son parámetros de configuración arbitrarios que puede cambiar un proveedor de configuración administrado. Si tu app se ejecuta en un perfil de trabajo, el administrador de TI puede cambiar la configuración administrada de tu app.

El proveedor de configuraciones administradas es otra app que se ejecuta en el mismo dispositivo. Por lo general, el administrador de TI controla esta app. El administrador de TI comunica los cambios de configuración a la app del proveedor de configuración administrada. Esa app, a su vez, cambia la configuración de tu app.

Para proporcionar configuraciones administradas de forma externa, sigue estos pasos:

  • Declara las configuraciones administradas en el manifiesto de tu app. De esta manera, el administrador de TI puede leer la configuración de la app a través de las APIs de Google Play.
  • Cada vez que se reanuda la app, usa el objeto RestrictionsManager para verificar las configuraciones administradas actuales y cambiar la IU y el comportamiento de la app para que se ajusten a esas configuraciones.
  • Escucha el intent ACTION_APPLICATION_RESTRICTIONS_CHANGED. Cuando recibas esta transmisión, verifica RestrictionsManager para ver cuáles son las configuraciones administradas actuales y realiza los cambios necesarios en el comportamiento de tu app.

Define las configuraciones administradas

Tu app puede admitir cualquier configuración administrada que quieras definir. Declaras las configuraciones administradas de la app en un archivo de configuraciones administradas y declaras el archivo de configuraciones en el manifiesto. Crear un archivo de configuración permite que otras apps examinen las configuraciones administradas que proporciona tu app. Los socios de EMM pueden leer la configuración de tu app con las APIs de Google Play.

Para definir las opciones de configuración remota de tu app, coloca el siguiente elemento en el elemento <application> de tu manifiesto:

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

Crea un archivo llamado app_restrictions.xml en el directorio res/xml de tu app. La estructura de ese archivo se describe en la referencia de RestrictionsManager. El archivo tiene un único elemento <restrictions> de nivel superior, que contiene un elemento secundario <restriction> para cada opción de configuración que tiene la app.

Nota: No crees versiones localizadas del archivo de configuración administrado. Tu app solo puede tener un archivo de configuración administrado, por lo que la configuración será coherente para tu app en todas las configuraciones regionales.

En un entorno empresarial, un EMM suele usar el esquema de configuración administrada para generar una consola remota para los administradores de TI, de modo que puedan configurar tu aplicación de forma remota.

El proveedor de configuración administrada puede consultar la app para encontrar detalles sobre las configuraciones disponibles de la app, incluido el texto de su descripción. El proveedor de configuraciones y el administrador de TI pueden cambiar las configuraciones administradas de tu app en cualquier momento, incluso cuando la app no se está ejecutando.

Por ejemplo, supongamos que tu app se puede configurar de forma remota para permitir o prohibir que descargue datos a través de una conexión celular. Tu app podría tener un elemento <restriction> como este:

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

Usas el atributo android:key de cada configuración para leer su valor desde un paquete de configuración administrado. Por este motivo, cada configuración debe tener una cadena de clave única, y la cadena no se puede localizar. Se debe especificar con un literal de cadena.

Nota: En una app de producción, android:title y android:description deben extraerse de un archivo de recursos localizado, como se describe en Localización con recursos.

Una app define restricciones con paquetes dentro de un bundle_array. Por ejemplo, una app con varias opciones de conexión de VPN podría definir cada configuración del servidor de VPN en un bundle, con varios paquetes agrupados en un array de paquetes:

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

Los tipos admitidos para el elemento android:restrictionType se enumeran en la Tabla 1 y se documentan en la referencia de RestrictionsManager y RestrictionEntry.

Tabla 1: Tipos de entradas y uso de restricciones

Tipo android:restrictionType Uso típico
TYPE_BOOLEAN "bool" Un valor booleano, verdadero o falso.
TYPE_STRING "string" Un valor de cadena, como un nombre.
TYPE_INTEGER "integer" Un número entero con un valor de MIN_VALUE a MAX_VALUE.
TYPE_CHOICE "choice" Un valor de cadena seleccionado de android:entryValues, que, por lo general, se presenta como una lista de selección única.
TYPE_MULTI_SELECT "multi-select" Es un array de cadenas con valores seleccionados de android:entryValues. Úsalo para presentar una lista de selección múltiple en la que se puede seleccionar más de una entrada, por ejemplo, para elegir títulos específicos para la lista de entidades permitidas.
TYPE_NULL "hidden" Es el tipo de restricción oculta. Usa este tipo para la información que se debe transferir, pero que no se debe presentar al usuario en la IU. Almacena un solo valor de cadena.
TYPE_BUNDLE_ARRAY "bundle_array" Úsalo para almacenar arrays de restricción bundles. Disponible en Android 6.0 (nivel de API 23).

Nota: android:entryValues son legibles por máquinas y no se pueden localizar. Usa android:entries para presentar valores legibles por humanos que se puedan localizar. Cada entrada debe tener un índice correspondiente en android:entryValues.

Cómo verificar las opciones de configuración administradas

Tu app no recibe notificaciones automáticamente cuando otras apps cambian su configuración. En su lugar, debes verificar cuáles son las configuraciones administradas cuando se inicia o se reanuda tu app, y escuchar un intent del sistema para saber si las configuraciones cambian mientras se ejecuta tu app.

Para conocer la configuración actual, tu app usa un objeto RestrictionsManager. Tu app debería verificar las configuraciones administradas actuales en los siguientes momentos:

Para obtener un objeto RestrictionsManager, obtén la actividad actual con getActivity() y, luego, llama al método Activity.getSystemService() de esa actividad:

Kotlin

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

Java

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

Una vez que tengas un RestrictionsManager, puedes obtener la configuración actual llamando a su método getApplicationRestrictions():

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

Nota: Para mayor comodidad, también puedes recuperar las configuraciones actuales con una UserManager llamando a UserManager.getApplicationRestrictions(). Este método se comporta exactamente igual que RestrictionsManager.getApplicationRestrictions().

El método getApplicationRestrictions() requiere la lectura del almacenamiento de datos, por lo que se debe hacer con moderación. No llames a este método cada vez que necesites conocer la configuración actual. En su lugar, debes llamarlo una vez cuando se inicie o se reanude la app, y almacenar en caché el paquete de configuraciones administradas recuperado. Luego, escucha el intent ACTION_APPLICATION_RESTRICTIONS_CHANGED para saber si la configuración cambia mientras la app está activa, como se describe en Cómo detectar cambios de configuración administrados.

Cómo leer y aplicar configuraciones administradas

El método getApplicationRestrictions() muestra una Bundle que contiene un par clave-valor para cada configuración establecida. Los valores son todos del tipo Boolean, int, String y String[]. Una vez que tengas las configuraciones Bundle administradas, puedes verificar la configuración actual con los métodos Bundle estándar para esos tipos de datos, como getBoolean() o getString().

Nota: Las configuraciones administradas Bundle contienen un elemento para cada configuración que estableció de forma explícita un proveedor de configuraciones administradas. Sin embargo, no puedes suponer que una configuración estará presente en el paquete solo porque definiste un valor predeterminado en el archivo en formato XML de las configuraciones administradas.

Depende de tu app tomar las medidas adecuadas según la configuración administrada actual. Por ejemplo, si tu app tiene una configuración que especifica si puede descargar datos a través de una conexión celular y descubres que la configuración está establecida en false, deberás inhabilitar la descarga de datos, excepto cuando el dispositivo tenga una conexión Wi-Fi, como se muestra en el siguiente código de ejemplo:

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
}

Para aplicar varias restricciones anidadas, lee la entrada de restricción bundle_array como una colección de objetos Parcelable y transmítela como Bundle. En este ejemplo, los datos de configuración de cada VPN se analizan y se usan para crear una lista de opciones de conexión del servidor:

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
}

Escucha los cambios de configuración administrados

Cada vez que se cambia la configuración administrada de una app, el sistema activa el intent ACTION_APPLICATION_RESTRICTIONS_CHANGED. Tu app debe detectar este intent para que puedas cambiar su comportamiento cuando cambie la configuración.

Nota: El intent ACTION_APPLICATION_RESTRICTIONS_CHANGED solo se envía a los objetos de escucha que se registran de forma dinámica, no a los que se declaran en el manifiesto de la app.

En el siguiente código, se muestra cómo registrar de forma dinámica un receptor de emisión para este 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: Por lo general, no es necesario que se notifique a tu app sobre los cambios de configuración cuando está en pausa. En su lugar, debes cancelar el registro de tu receptor de emisión cuando la app esté detenida. Cuando se reanuda la app, primero debes verificar las configuraciones administradas actuales (como se explica en Cómo verificar las configuraciones administradas) y, luego, registrar tu receptor de emisión para asegurarte de recibir notificaciones sobre los cambios de configuración que se producen mientras la app está activa.

Cómo enviar comentarios sobre la configuración administrada a los EMM

Después de aplicar cambios de configuración administrados a tu app, se recomienda notificar a los EMMs el estado del cambio. Android admite una función llamada estados de app con claves, que puedes usar para enviar comentarios cada vez que tu app intenta aplicar cambios de configuración administrada. Estos comentarios pueden confirmar que tu app configuró correctamente las configuraciones administradas o pueden incluir un mensaje de error si la app no pudo aplicar los cambios especificados.

Los proveedores de EMM pueden recuperar estos comentarios y mostrarlos en sus consolas para que los administradores de TI los vean. Consulta Cómo enviar comentarios sobre la app a EMM para obtener más información sobre el tema, incluida una guía detallada sobre cómo agregar compatibilidad con comentarios a tu app.

Muestras de código adicionales

En el ejemplo de ManagedConfigurations, se demuestra aún más el uso de las APIs que se abordan en esta página.

Cómo incluir apps en una lista de entidades permitidas o bloquearlas en el perfil personal

Es posible que las tiendas de aplicaciones de terceros deseen usar las configuraciones administradas para tener una forma confiable de aplicar una lista de bloqueo o de entidades permitidas de apps al perfil personal y a la función para consumidores de Espacio privado, que es un espacio personal adicional para que los usuarios guarden sus apps sensibles. Si desarrollas una tienda de aplicaciones para uso empresarial y quieres usar esta función, envía este formulario para expresar tu interés y selecciona Interés en la lista de entidades permitidas de tiendas de aplicaciones de terceros como motivo de la respuesta en el formulario.