Cómo compilar una app que se ejecuta en un perfil de trabajo

¿Qué es un perfil de trabajo?

Un perfil de trabajo es un perfil secundario que se puede habilitar en el dispositivo personal de un usuario cuando una empresa permite que sus empleados utilicen sus dispositivos personales para trabajar.

Un administrador de IT puede controlar los perfiles de trabajo, y la funcionalidad disponible para ellos se configura de manera independiente a las funciones del perfil principal del usuario. Este enfoque permite que las organizaciones controlen el entorno en el que las apps y datos específicos de la empresa se ejecutan en el dispositivo de un usuario, a la vez que permiten que sus usuarios utilicen sus aplicaciones y perfiles personales.

¿Cómo afecta a tu app? Cualquier app se puede instalar en un perfil de trabajo, por lo que la app puede tener restricciones de tiempo de ejecución, así como cambios de comportamiento. También, te recomendamos que te asegures de que tu app sea confiable si se usa con fines laborales. Incluso si tu app se ejecuta en un perfil personal, un perfil de trabajo puede afectar la manera en que debe comportarse tu app.

Requisitos previos

Este codelab se diseñó para desarrolladores de Android con habilidades básicas e intermedias.

Se supone que ya compilaste una app, usaste Android Studio y la probaste en un dispositivo o emulador.

Actividades

En este codelab, modificarás una app para que ofrezca la mejor experiencia del usuario cuando se instale en un dispositivo con un perfil de trabajo. Aprenderás a configurar tu app para que haga lo siguiente:

  • Procese los contactos personales y de trabajo al mismo tiempo.
  • Cambie entre perfiles personales y de trabajo desde la misma app.

e69c26cfc305d675.png

Requisitos

  • Un dispositivo Android no administrado (que no pertenezca a una organización ni que esté administrado por una).

Cómo configurar un dispositivo de prueba

Para este codelab, te recomendamos que uses un dispositivo físico. Sin embargo, puedes configurar un emulador de la misma manera que se menciona más adelante.

TestDPC

La app TestDPC fue compilada por Google para permitirte simular y probar un entorno administrado en tu propio dispositivo. Esta herramienta configurará un perfil de trabajo y te brindará controles para habilitar o inhabilitar funciones determinadas en el dispositivo, como si fueses un administrador de IT.

Cómo instalar la app TestDPC

En tu dispositivo, abre Google Play Store y descarga la app TestDPC.

Cómo configurar un perfil de trabajo

Una vez que se instale la app TestDPC, observarás 2 íconos en el dispositivo, un ícono de configuración y el ícono de la app TestDPC. Presiona el ícono de configuración y sigue los pasos.

Ahora, tienes dos perfiles independientes: uno para las apps personales y otro para las apps de trabajo. Puedes cambiar entre estos por medio de las pestañas en la parte superior de la lista de apps.

Ten en cuenta que cada perfil tiene su propia app de Play Store. Puedes identificar las apps de trabajo desde la foto pequeña de maletín en la parte superior del ícono de selector.

153e3b8dbfb4a86e.gif

Puedes instalar apps mediante Play Store como lo sueles hacer, y según la versión de Play Store en la que inicias la app (perfil personal o de trabajo), esta app solo se instalará en ese perfil. Las apps también pueden existir en ambos perfiles cuando se instalan desde ambos Play Store. En ese caso, cada versión de la app tendrá espacios de almacenamiento y configuración completamente aislados.

Cuando ejecutes una app en Android Studio para instalarla, se instalará en ambos perfiles de forma predeterminada.

Configura algunos contactos de prueba para usar en la app de demostración:

  1. Inicia la app de Contactos del dispositivo desde el perfil personal.
  2. Agrega algunos contactos de prueba que puedas identificar como contactos personales.
  3. Inicia la app de Contactos desde el perfil de trabajo. (No verás ninguno de los contactos personales que recién agregaste).
  4. Agrega algunos contactos de prueba que puedas identificar como contactos de trabajo.

Una vez que estés satisfecho con los contactos que configuraste, prueba el código de inicio de la app de demostración.

  1. Para obtener la app de ejemplo, haz lo siguiente:
  • clona el repositorio desde GitHub
$  git clone https://github.com/a-samak/work-profile-codelab
  • o descarga el repositorio como un archivo ZIP

Download Zip

  1. Una vez que lo hayas descargado, navega hasta la carpeta del proyecto y cambia a la rama starter.
$  git checkout starter
  1. Abre y ejecuta la app en Android Studio.

Cuando inicies la app por primera vez, se verá de la siguiente manera:

f9779ab476511718.png

Probar

Cuando ejecutas la app desde Android Studio en un dispositivo o emulador, se instala en ambos perfiles. Si lo deseas, puedes borrar la app de un perfil y dejarla en el otro.

Prueba ejecutar la app en tu perfil personal. Verás todos los contactos personales en la lista, pero ninguno de los contactos de trabajo. Ahora, prueba ejecutar la app en tu perfil de trabajo. Solo verás los contactos de trabajo, pero ninguno de los contactos personales.

Al final de este codelab, tu app mostrará contactos personales y de trabajo cuando se ejecute en el perfil personal. También podrás cambiar entre perfiles. Para ello, inicia otra instancia de la app en el otro perfil desde la misma app.

Cuando cargues contactos con ContactsContract.Contacts.CONTENT_URI, la app decidirá qué contactos mostrar, según el perfil en el que se esté ejecutando. Sin embargo, en muchos casos, es posible que desees que la app cargue ambas listas de contactos al mismo tiempo. Por ejemplo, es posible que el usuario desee compartir un elemento personal (foto, documento) con un colega del trabajo. Para ello, deberás recuperar ambas listas de contactos.

Abre MainActivity.kt.

El método onCreateLoader() se encarga de crear el elemento CursorLoader para recuperar y cargar los contactos. Por el momento, solo muestra un elemento CursorLoader con el objeto ContentURI predeterminado. Llamarás a este método dos veces, una para los contactos personales y la otra para los contactos de trabajo. Con el objeto de diferenciarlos, pasaremos un ID diferente a onCreateLoader() para cada caso. Deberás verificar el ID que se pasó al método a fin de decidir qué ContentURI usar.

Primero, cambia el valor de la variable ContentURI según el valor de ID que se pasó al método. En el caso de PERSONAL_CONTACTS_LOADER_ID, asígnalo al objeto ContactsContract.Contacts.CONTENT_URI predeterminado. De lo contrario, compilarás un elemento ENTERPRISE_CONTENT_FILTER_URI como se describe aquí.

ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()

Observarás que, como se trata de un URI de filtro de contenido, el compilador necesita un filtro de búsqueda (frase de búsqueda) para usarlo cuando se realizan búsquedas o se cargan los contactos.

Por ahora, codifica la frase de búsqueda para que sea cualquier nombre que comience con la letra "a".

val nameFilter = Uri.encode("a") // names that start with a

También, debes especificar el directorio de contactos en el que se realizará la búsqueda. Usarás el directorio ENTERPRISE_DEFAULT que busca contactos almacenados, de manera local, en el dispositivo.

El método onCreateLoader() debería verse de la siguiente manera:

override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
        val nameFilter = Uri.encode("a") // names that start with W
        val contentURI = when (id) {
            PERSONAL_CONTACTS_LOADER_ID -> ContactsContract.Contacts.CONTENT_URI
            else -> {
                ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()
            }
        }
        return CursorLoader(
            this, contentURI, arrayOf(
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
            ), null, null, null
        )
    }

Ahora, debes inicializar otro elemento Loader con un valor nuevo de ID para activar el método anterior.

Primero, crea un nuevo valor de ID constante para los contactos de trabajo en la parte superior de MainActivity:

const val WORK_CONTACTS_LOADER_ID = 1

Luego, en initLoaders(), usa LoaderManager para inicializar un elemento Loader nuevo con el ID nuevo que se creó anteriormente:

private fun initLoaders() {
        LoaderManager.getInstance(this).
            initLoader(PERSONAL_CONTACTS_LOADER_ID, null, this)
        LoaderManager.getInstance(this).
            initLoader(WORK_CONTACTS_LOADER_ID, null, this)
    }

Todos los demás métodos deben funcionar de la misma manera, ya que el cursor de datos de ambos cargadores tiene la misma estructura.

Probar

Ejecuta la app en el perfil personal. Ahora, puedes ver los contactos personales y de trabajo.

f9779ab476511718.png 7e4846e179664d66.png

¿Qué sucede con el perfil de trabajo?

Si ejecutas la app en el perfil de trabajo, solo verás los contactos de trabajo y ninguno de los personales. Esto se debe a que uno de los objetivos principales de los perfiles de trabajo es proteger la privacidad del usuario. Por este motivo, en general, las apps de trabajo no pueden acceder a ningún tipo de información personal desde el perfil personal.

9b7ddeec64957963.png

Android incluye API para iniciar otra instancia de tu app en un perfil diferente, lo que permite que los usuarios cambien entre las cuentas. Por ejemplo, una app de correo electrónico puede proporcionar una IU que le permita al usuario pasar del perfil personal al de trabajo para acceder a dos cuentas de correo electrónico.

Todas las apps pueden llamar a estas API para lanzar la actividad principal de la misma app si ya está instalada en el otro perfil.

Para agregar a tu app el cambio de cuenta en diferentes perfiles, primero, debes agregar un botón a nuestro diseño de actividad principal, de modo que los usuarios puedan cambiar de perfil.

Abre activity_main.xml y agrega un widget de botón debajo del widget de la vista de reciclador:

<androidx.appcompat.widget.AppCompatButton
        android:id="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/contacts_rv"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

Vuelve a MainActivity.kt y configura el evento de clic del botón para cambiar de perfil.

Para ello, primero, debes obtener el servicio del sistema CrossProfileApps:

val crossProfileApps = getSystemService(CrossProfileApps::class.java)

Esta clase brinda todas las API que necesitas para implementar una función de cambio de perfil. Para recuperar la lista de perfiles del usuario, llama a targetUserProfiles, que mostrará todos los demás perfiles en los que se instaló esta app.

val userHandles = crossProfileApps.targetUserProfiles

Ahora, puedes usar el primer elemento userHandle que se muestra e iniciar la app en el otro perfil.

crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )

Incluso, puedes obtener un texto localizado que le solicite al usuario cambiar de perfil y usarlo para configurar el valor del texto del botón.

val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())

Ahora, une todas estas partes, que las agregarás a MainActivity.kt:

val crossProfileApps = getSystemService(CrossProfileApps::class.java)
        val userHandles = crossProfileApps.targetUserProfiles
        val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())
        button = findViewById<AppCompatButton>(R.id.button).apply {
            text = label
            setOnClickListener {
                crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )
            }
        }

Probar

Si ejecutas la app ahora, observarás el botón en la parte inferior que indica que está lista para cambiar al perfil de trabajo o al perfil personal, según desde dónde hayas iniciado la app.

Si haces clic en ese botón, se iniciará la app en el otro perfil.

d904de4fdc0d091b.png 4835ce56fcf10ea1.png

Modificaste con éxito una app que funciona tanto en el perfil personal como en el perfil de trabajo, reconoce cuando hay un perfil de trabajo instalado y recupera los contactos de trabajo incluso cuando se ejecuta en el modo personal.

Además, implementaste una manera para que los usuarios cambien entre el perfil de trabajo y el perfil personal de la misma app mientras ejecutan la app sin tener que cerrarla ni reiniciarla desde el perfil correcto. Te recomendamos que ayudes a los usuarios que usan tu app de manera diferente en los distintos perfiles.

Más información