Cómo crear un tipo de cuenta personalizado

Hasta ahora, hablamos sobre el acceso a las APIs de Google, que utilizan cuentas y usuarios definidos por Google. Sin embargo, si tienes tu propio servicio en línea, no tendrá usuarios ni Cuentas de Google. Entonces, ¿qué debes hacer? Resulta que es relativamente sencillo instalar nuevos tipos de cuenta en el dispositivo de un usuario. En esta lección, se explica cómo crear un tipo de cuenta personalizado que funcione de la misma manera que las cuentas integradas.

Cómo implementar un código de cuenta personalizado

Lo primero que necesitarás es una forma de obtener las credenciales del usuario. Esto puede ser tan simple como un cuadro de diálogo que solicita un nombre y una contraseña. También podría tratarse de un procedimiento más inusual, como una contraseña de un solo uso o un escaneo biométrico. De cualquier manera, es tu responsabilidad implementar un código que cumpla con las siguientes condiciones:

  1. Recopilar credenciales del usuario
  2. Autenticar las credenciales con el servidor
  3. Almacenar las credenciales en el dispositivo

Por lo general, una sola actividad puede encargarse de los tres requisitos. A esto lo llamaremos actividad de autenticador.

Debido a que necesitan interactuar con el sistema de AccountManager, las actividades de autenticador tienen ciertos requisitos que las actividades normales no poseen. Para facilitar el proceso, el framework de Android proporciona una clase base, AccountAuthenticatorActivity, que puedes extender para crear tu propio autenticador personalizado.

La manera en la que abordas los dos primeros requisitos de una actividad de autenticación, la recopilación y autenticación de credenciales, depende completamente de ti. (Después de todo, si hubiera una sola forma de hacerlo, no habría necesidad de tipos de cuenta "personalizados"). El tercer requisito tiene una implementación canónica y bastante simple:

Kotlin

Account(username, your_account_type).also { account ->
    accountManager.addAccountExplicitly(account, password, null)
}

Java

final Account account = new Account(username, your_account_type);
accountManager.addAccountExplicitly(account, password, null);

Aborda la seguridad con inteligencia

Es importante comprender que AccountManager no es un servicio de encriptación ni un llavero. Almacena las credenciales de la cuenta tal como las pasas, en texto sin formato. En la mayoría de los dispositivos, esto no es una preocupación particular, ya que las almacena en una base de datos a la que solo se puede acceder con permisos de administrador. Sin embargo, en un dispositivo con derechos de administrador, cualquier persona con acceso adb al dispositivo puede leer las credenciales.

Con esto en mente, no debes pasar la contraseña real del usuario a AccountManager.addAccountExplicitly(). En cambio, debes almacenar un token seguro criptográficamente que sería de uso limitado para un atacante. Si tus credenciales de usuario protegen algo valioso, considera hacer algo similar con cuidado.

Recuerda: Cuando se trata del código de seguridad, sigue la regla "Mythbusters": ¡no pruebes esto en casa! Consulta a un profesional de seguridad antes de implementar cualquier código de cuenta personalizado.

Ahora que ya no hay advertencias de seguridad, es hora de volver al trabajo. Ya implementaste la mayor parte de tu código de cuenta personalizado; lo que queda son los de mantenimiento.

Cómo extender AbstractAccountAuthenticator

Para que AccountManager funcione con el código de tu cuenta personalizado, necesitas una clase que implemente las interfaces que AccountManager espera. Se trata de la clase de autenticador.

La forma más fácil de crear una clase de autenticador es extender AbstractAccountAuthenticator e implementar sus métodos abstractos. Si hiciste las lecciones anteriores, los métodos abstractos de AbstractAccountAuthenticator deberían resultarte familiares: son el opuesto de los métodos que llamaste en la lección anterior para obtener información de cuentas y tokens de autorización.

La implementación correcta de una clase de autenticador requiere una serie de fragmentos de código separados. En primer lugar, AbstractAccountAuthenticator tiene siete métodos abstractos que debes anular. En segundo lugar, debes agregar un filtro de intents para "android.accounts.AccountAuthenticator" al manifiesto de tu aplicación (que se muestra en la siguiente sección). Por último, debes proporcionar dos recursos XML que definan, entre otros aspectos, el nombre de tu tipo de cuenta personalizado y el ícono que el sistema mostrará junto a las cuentas de este tipo.

En la documentación de AbstractAccountAuthenticator, puedes encontrar una guía paso a paso para implementar de manera correcta una clase de autenticador y los archivos en formato XML.

Si tu actividad de autenticación necesita algún parámetro de inicialización especial, puedes adjuntarlo al intent mediante Intent.putExtra().

Cómo crear un servicio de autenticador

Ahora que tienes una clase de autenticador, necesitas un lugar donde usarla. Los autenticadores de cuentas deben estar disponibles para varias aplicaciones y funcionar en segundo plano, por lo que deben ejecutarse dentro de un Service. A esto lo llamaremos servicio autenticador.

Tu servicio de autenticador puede ser muy simple. Lo único que debes hacer es crear una instancia de tu clase de autenticador en onCreate() y llamar a getIBinder() en onBind().

No olvides agregar una etiqueta <service> a tu archivo de manifiesto, agregar un filtro de intents para el intent AccountAutenticador y declarar el autenticador de la cuenta:

<service ...>
   <intent-filter>
      <action android:name="android.accounts.AccountAuthenticator" />
   </intent-filter>
   <meta-data android:name="android.accounts.AccountAuthenticator"
             android:resource="@xml/authenticator" />
</service>

Cómo distribuir el servicio

¡Listo! El sistema ahora reconoce tu tipo de cuenta, junto con todos los tipos de cuentas reconocidas, como “Google” y “Corporate”. Puedes usar la página de configuración de Cuentas y sincronización para agregar una cuenta, y las apps que soliciten cuentas de tu tipo personalizado podrán enumerar y autenticar como lo harían con cualquier otro tipo de cuenta.

Por supuesto, todo esto supone que el servicio de tu cuenta esté realmente instalado en el dispositivo. Si solo una app accede al servicio, no es un gran problema, solo debes empaquetar el servicio en la app. Sin embargo, si quieres que más de una app use el servicio de tu cuenta, las cosas se complican. No quieres empaquetar el servicio con todas tus apps y tener varias copias de él ocupando espacio en el dispositivo del usuario.

Una solución es colocar el servicio en un pequeño APK especial. Cuando una app desea usar tu tipo de cuenta personalizada, puede verificar el dispositivo para ver si está disponible. De lo contrario, puede dirigir al usuario a Google Play para descargar el servicio. Al principio, esto puede parecer un gran problema, pero, en comparación con la alternativa de volver a ingresar las credenciales para cada app que usa tu cuenta personalizada, es muy fácil.