Perfiles de trabajo

La plataforma de Android permite que los dispositivos tengan perfiles de trabajo (a veces denominados perfiles administrados). Un administrador de TI controla un perfil de trabajo, y la funcionalidad disponible se configura por separado de la funcionalidad del perfil principal del usuario. Este enfoque permite que las organizaciones controlen el entorno en el que se ejecutan apps y datos específicos de la empresa en el dispositivo de un usuario, al tiempo que permite que los usuarios usen sus apps y perfiles personales.

En esta lección, se muestra cómo modificar tu aplicación para que funcione de manera confiable en un dispositivo con un perfil de trabajo. No necesitas hacer nada más que las prácticas recomendadas comunes para el desarrollo de apps. Sin embargo, algunas de estas prácticas recomendadas se vuelven especialmente importantes en los dispositivos con perfiles de trabajo. En este documento, se destacan los problemas que debes tener en cuenta.

Descripción general

A menudo, los usuarios quieren usar sus dispositivos personales en un entorno empresarial. Esta situación puede presentar a las organizaciones un dilema. Si el usuario puede usar su propio dispositivo, la organización deberá preocuparse por que la información confidencial (como contactos y correos electrónicos de los empleados) esté en un dispositivo que la organización no controla.

Para solucionar esta situación, Android 5.0 (nivel de API 21) permite a las organizaciones configurar perfiles de trabajo. Si un dispositivo tiene un perfil de trabajo, el administrador de TI controla la configuración del perfil. El administrador de TI puede elegir qué apps se permiten para ese perfil y controlar solo las funciones del dispositivo que están disponibles para el perfil.

Si un dispositivo tiene un perfil de trabajo, hay consecuencias para las apps que se ejecutan en él, independientemente del perfil en el que se ejecute la app:

  • De forma predeterminada, la mayoría de los intents no se comparten de un perfil a otro. Si una app que se ejecuta en el perfil activa un intent, no hay un controlador para el intent en ese perfil y no se permite que el intent se dirija al otro perfil debido a sus restricciones, la solicitud falla y la app puede cerrarse de forma inesperada.
  • El administrador de TI del perfil puede limitar qué apps del sistema están disponibles en el perfil de trabajo. Esta restricción también puede provocar que no haya controladores para algunos intents comunes en el perfil de trabajo.
  • Dado que los perfiles personal y de trabajo tienen áreas de almacenamiento separadas, un URI de archivo válido en un perfil no lo es en el otro. Cualquier intent activado en un perfil puede controlarse en el otro (según la configuración del perfil), por lo que no es seguro adjuntar URI de archivos a intents.

Evita los intents con errores

En un dispositivo con un perfil de trabajo, existen restricciones respecto de si los intents pueden pasar de un perfil a otro. En la mayoría de los casos, cuando se activa un intent, se controla en el mismo perfil en el que se activa. Si no hay un controlador para el intent en ese perfil, este no se maneja, y la app que lo activó puede cerrarse de forma inesperada, incluso si hay un controlador para el intent en el otro perfil.

El administrador de perfiles puede elegir qué intents pueden cruzarse de un perfil a otro. Debido a que el administrador de TI toma esta decisión, no hay forma de que sepas con anticipación qué intents pueden cruzar este límite. El administrador de TI establece esta política y puede cambiarla en cualquier momento.

Antes de que tu app inicie una actividad, debes verificar que haya una resolución adecuada. Puedes verificar que haya una resolución aceptable llamando a Intent.resolveActivity(). Si no hay forma de resolver el intent, el método muestra null. Si el método muestra un valor no nulo, hay al menos una forma de resolver el intent y es seguro activarlo. En este caso, el intent se podría resolver debido a que hay un controlador en el perfil actual o porque el intent tiene permitido pasar a un controlador en el otro perfil. (Para obtener más información sobre la resolución de intents, consulta Intents comunes).

Por ejemplo, si la app necesita establecer temporizadores, debería verificar que haya un controlador válido para el intent ACTION_SET_TIMER. Si la app no puede resolver el intent, debería realizar una acción adecuada (como mostrar un mensaje de error).

Kotlin

fun startTimer(message: String, seconds: Int) {

    // Build the "set timer" intent
    val timerIntent = Intent(AlarmClock.ACTION_SET_TIMER).apply {
        putExtra(AlarmClock.EXTRA_MESSAGE, message)
        putExtra(AlarmClock.EXTRA_LENGTH, seconds)
        putExtra(AlarmClock.EXTRA_SKIP_UI, true)
    }

    // Check if there's a handler for the intent
    if (timerIntent.resolveActivity(packageManager) == null) {

        // Can't resolve the intent! Fail this operation cleanly
        // (perhaps by showing an error message)

    } else {
        // Intent resolves, it's safe to fire it off
        startActivity(timerIntent)

    }
}

Java

public void startTimer(String message, int seconds) {

    // Build the "set timer" intent
    Intent timerIntent = new Intent(AlarmClock.ACTION_SET_TIMER)
            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);

    // Check if there's a handler for the intent
    if (timerIntent.resolveActivity(getPackageManager()) == null) {

        // Can't resolve the intent! Fail this operation cleanly
        // (perhaps by showing an error message)

    } else {
        // Intent resolves, it's safe to fire it off
        startActivity(timerIntent);

    }
}

Cómo compartir archivos entre perfiles

En ocasiones, una app necesita proporcionar a otras apps acceso a sus propios archivos. Por ejemplo, una app de galería de imágenes podría querer compartir sus imágenes con editores de imágenes. Por lo general, existen dos maneras de compartir un archivo: con un URI de archivo o un URI de contenido.

El URI de un archivo comienza con el prefijo file:, seguido de la ruta de acceso absoluta del archivo en el almacenamiento del dispositivo. Sin embargo, debido a que el perfil de trabajo y el personal usan áreas de almacenamiento separadas, un URI de archivo que es válido en un perfil no lo es en el otro. Esta situación significa que si adjuntas un URI de archivo a un intent, y el intent se maneja en el otro perfil, el controlador no podrá acceder al archivo.

En su lugar, debes compartir archivos con URI de contenido. Los URI de contenido identifican el archivo de una manera más segura y fácil de compartir. El URI de contenido incluye la ruta de acceso al archivo, pero también la autoridad que lo proporciona y un número de ID que lo identifica. Puedes generar un ID de contenido para cualquier archivo mediante un FileProvider. Luego, puedes compartir ese Content ID con otras apps (incluso en el otro perfil). El destinatario puede usar el ID de contenido para obtener acceso al archivo real.

Por ejemplo, a continuación, se muestra cómo obtendrías el URI de contenido para un URI de archivo específico:

Kotlin

// Open File object from its file URI
val fileToShare = File(fileUriToShare)

val contentUriToShare: Uri = FileProvider.getUriForFile(
        context,
        "com.example.myapp.fileprovider",
        fileToShare
)

Java

// Open File object from its file URI
File fileToShare = new File(fileUriToShare);

Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
        "com.example.myapp.fileprovider", fileToShare);

Cuando llamas al método getUriForFile(), debes incluir la autoridad del proveedor de archivos (en este ejemplo, "com.example.myapp.fileprovider"), que se especifica en el elemento <provider> del manifiesto de la app. Para obtener más información sobre cómo compartir archivos con URI de contenido, consulta Cómo compartir archivos.

Cómo detectar notificaciones

Por lo general, una app proporciona una subclase NotificationListenerService para recibir devoluciones de llamada del sistema sobre los cambios en las notificaciones. Los dispositivos con perfiles de trabajo pueden afectar el funcionamiento de NotificationListenerService con tu app.

En un perfil de trabajo

No puedes usar un NotificationListenerService de una app que se ejecute en el perfil de trabajo. Cuando tu app se ejecuta en un perfil de trabajo, el sistema ignora el NotificationListenerService de tu app. Sin embargo, las apps que se ejecutan en el perfil personal pueden escuchar notificaciones.

En un perfil personal

Cuando tu app se ejecuta en el perfil personal, es posible que no recibas notificaciones de apps que se ejecutan en el perfil de trabajo. De forma predeterminada, todas las apps de perfil personal reciben devoluciones de llamada, pero un administrador de TI puede incluir en la lista de entidades permitidas una o más apps de perfil personal que tengan permitido detectar cambios en las notificaciones. Luego, el sistema bloquea las apps que no están incluidas en la lista de entidades permitidas. En Android 8.0 (nivel de API 26) o versiones posteriores, un controlador de política de dispositivo (DPC) que administra un perfil de trabajo podría impedir que tu app escuche las notificaciones del perfil de trabajo con el método DevicePolicyManager setPermittedCrossProfileNotificationListeners(). Tu app seguirá recibiendo devoluciones de llamada sobre notificaciones publicadas en el perfil personal.

Prueba la compatibilidad de tu app con los perfiles de trabajo

Debes probar tu app en un entorno de perfil de trabajo para detectar problemas que podrían hacer que tu app falle en un dispositivo con perfiles de trabajo. En particular, realizar pruebas en un dispositivo con perfil de trabajo es una buena manera de asegurarte de que tu app maneje correctamente los intents: no activar intents que no se puedan controlar, no adjuntar URIs que no funcionen entre perfiles, etcétera.

Proporcionamos una app de ejemplo, TestDPC, que puedes usar para configurar un perfil de trabajo en un dispositivo Android que ejecute Android 5.0 (nivel de API 21) y versiones posteriores. Esta app te ofrece una manera sencilla de probar tu app en un entorno de perfil de trabajo. También puedes usar esta app para configurar el perfil de trabajo de la siguiente manera:

  • Especificar qué apps predeterminadas están disponibles en el perfil administrado
  • Configura qué intents pueden cruzarse de un perfil a otro

Si instalas manualmente una app a través de un cable USB en un dispositivo que tiene un perfil de trabajo, la app se instalará en el perfil personal y en el de trabajo. Una vez que instales la app, podrás probarla en las siguientes condiciones:

  • Si una app predeterminada (por ejemplo, la app de cámara) maneja un intent normalmente, inhabilita esa app en el perfil de trabajo y verifica que la app lo controle correctamente.
  • Si activas un intent que espera que lo controle otra app, intenta habilitar o inhabilitar el permiso de ese intent para que se cruce de un perfil a otro. Verifica que la app se comporte correctamente en ambas circunstancias. Si no se permite que el intent se cruce entre perfiles, verifica el comportamiento de la app cuando haya un controlador adecuado en el perfil de la app y cuando no lo haya. Por ejemplo, si tu app activa un intent relacionado con un mapa, prueba cada una de las siguientes situaciones:
    • El dispositivo permite que los intents de mapa se crucen de un perfil a otro y que haya un controlador adecuado en el otro (el perfil en el que no se ejecuta la app).
    • El dispositivo no permite que los intents de mapa se crucen entre perfiles, pero hay un controlador adecuado en el perfil de la app.
    • El dispositivo no permite que los intents de mapa se crucen entre perfiles y no hay un controlador adecuado para esos intents en el perfil del dispositivo.
  • Si adjuntas contenido a un intent, verifica que se comporte de manera correcta tanto cuando se controla en el perfil de la app como cuando se cruza entre perfiles.

Prueba los perfiles de trabajo: sugerencias y trucos

Hay algunos trucos que pueden resultarte útiles para probar en un dispositivo de perfil de trabajo.

  • Como se indicó, cuando transfieres una app en un dispositivo con perfil de trabajo, esta se instala en ambos perfiles. Si lo deseas, puedes borrar la app de un perfil y dejarla en el otro.
  • La mayoría de los comandos del administrador de actividades disponibles en el shell de Android Debug Bridge (adb) admiten la marca --user, que te permite especificar con qué usuario ejecutar. Cuando especificas un usuario, puedes elegir si deseas ejecutarlo como el usuario principal no administrado o como perfil de trabajo. Para obtener más información, consulta Comandos de shell de ADB.
  • Para buscar a los usuarios activos en un dispositivo, usa el comando list users del administrador de paquetes adb. El primer número de la string de salida es el ID del usuario, que puedes usar con la marca --user. Para obtener más información, consulta Comandos de shell de ADB.

Por ejemplo, para encontrar a los usuarios en un dispositivo, debes ejecutar este comando:

$ adb shell pm list users
UserInfo{0:Drew:13} running
UserInfo{10:Work profile:30} running

En este caso, el usuario principal("Drew") tiene el ID de usuario 0 y el perfil de trabajo tiene el ID de usuario 10. Para ejecutar una app en el perfil de trabajo, deberías usar un comando como el siguiente:

$ adb shell am start --user 10 \
-n "com.example.myapp/com.example.myapp.testactivity" \
-a android.intent.action.MAIN -c android.intent.category.LAUNCHER