Cómo obtener el Android ID o IMEI con Kotlin: una guía detallada para desarrolladores

En el vasto ecosistema de Android, la identificación de dispositivos es un tema recurrente y, a menudo, complejo. Desde las necesidades de marketing y análisis hasta la seguridad y la prevención de fraudes, muchos desarrolladores se han visto en la encrucijada de querer identificar un dispositivo de manera única y persistente. Tradicionalmente, se pensaba en el IMEI o el Android ID como las soluciones directas. Sin embargo, la evolución de la plataforma Android, impulsada por una creciente preocupación por la privacidad del usuario, ha transformado drásticamente la forma en que podemos acceder a estos identificadores. Esta guía se adentrará en las particularidades del Android ID y el IMEI, explorando cómo (y si) se pueden obtener con Kotlin, siempre con un enfoque en las mejores prácticas, la seguridad y, sobre todo, el respeto por la privacidad. Prepárate para desentrañar los misterios de la identificación de dispositivos Android en la era moderna.

Entendiendo el Android ID y el IMEI

Vibrant fruit stand with melons, citrus, and pineapples at a Mexican market.

Antes de sumergirnos en el código y los permisos, es fundamental comprender qué representan el Android ID y el IMEI, sus diferencias fundamentales y sus implicaciones.

¿Qué es el Android ID?

El Android ID es un identificador único asignado a cada instalación de Android. Se trata de un número de 64 bits (String hexadecimal) que se genera la primera vez que se inicia un dispositivo y permanece constante para esa combinación específica de usuario, dispositivo y aplicación que lo solicita. Es importante destacar que, a partir de Android 8.0 (Oreo), el Android ID es específico para cada perfil de usuario y aplicación. Esto significa que si diferentes aplicaciones en el mismo dispositivo solicitan el Android ID, cada una podría obtener un valor diferente, o al menos un valor diferente al que obtendría un usuario distinto en el mismo dispositivo o un usuario en un perfil de trabajo.

Su naturaleza principal es servir como un identificador único para una aplicación en particular instalada en un dispositivo particular. Esto lo hace útil para propósitos de análisis internos de la aplicación, configuración de preferencias específicas del dispositivo para esa app o, en algunos casos, para la gestión de licencias. Sin embargo, no es un identificador a prueba de balas para el "dispositivo físico" en sí, ya que se restablece si el usuario realiza un restablecimiento de fábrica del dispositivo o si la aplicación se desinstala y se vuelve a instalar (aunque en algunos escenarios, puede persistir para la misma aplicación si no se elimina la carpeta de datos de la app). Para más detalles técnicos, puedes consultar la documentación oficial de Android sobre Settings.Secure.ANDROID_ID. Esta ambigüedad ha llevado a muchos desarrolladores a buscar alternativas más robustas, lo que nos lleva al IMEI.

¿Qué es el IMEI?

El IMEI (International Mobile Equipment Identity) es un número único de 15 dígitos que identifica de manera global y exclusiva a un dispositivo móvil. Es como el número de serie de un teléfono, pero estandarizado a nivel mundial. Para una comprensión más profunda de su estructura y uso a nivel global, puedes consultar la entrada de Wikipedia sobre IMEI. Este identificador se encuentra grabado en el hardware del dispositivo y no cambia a menos que se reemplace el chip de módem o la placa base, algo que no suele ocurrir. Su propósito principal es identificar el equipo en la red GSM, UMTS o LTE, lo que permite a las operadoras bloquear teléfonos robados o perdidos, rastrear dispositivos para fines de garantía o incluso habilitar servicios específicos para un terminal concreto.

La singularidad y persistencia del IMEI lo convirtieron, durante mucho tiempo, en el "santo grial" de la identificación de dispositivos para los desarrolladores. Era visto como la forma más fiable de identificar un dispositivo físico sin ambigüedades. Sin embargo, precisamente por estas características, el acceso al IMEI se convirtió en un foco de preocupación en términos de privacidad. Si una aplicación podía obtener el IMEI, teóricamente podría rastrear al usuario a través de múltiples aplicaciones y servicios sin su consentimiento explícito o la posibilidad de resetear este identificador, lo que plantea serios problemas de privacidad y seguridad. Este fue un factor clave para que Google endureciera las políticas de acceso a este identificador.

En resumen, mientras que el Android ID es un identificador más efímero y con alcance limitado (por aplicación/usuario), el IMEI es un identificador de hardware global y persistente. La diferencia en su naturaleza y las implicaciones de privacidad asociadas han llevado a tratamientos muy distintos por parte del sistema operativo Android.

Consideraciones de privacidad y permisos

La historia del acceso a identificadores de dispositivos en Android es una crónica de la evolución de la privacidad. Google ha implementado cambios significativos a lo largo de las versiones para proteger los datos de los usuarios.

La evolución de la privacidad en Android

En los primeros días de Android, el acceso a identificadores como el IMEI era relativamente sencillo. Sin embargo, a medida que los smartphones se volvieron omnipresentes y la recolección de datos se disparó, creció la conciencia sobre los riesgos de privacidad asociados con el rastreo persistente e inmutable de los usuarios.

  • Android 6.0 (Marshmallow): Introdujo el modelo de permisos en tiempo de ejecución. Esto significaba que los usuarios podían aprobar o denegar permisos individuales cuando la aplicación los solicitaba, en lugar de hacerlo solo durante la instalación. Para el acceso al IMEI, esto significó que las aplicaciones necesitaban el permiso READ_PHONE_STATE y el usuario debía otorgarlo explícitamente.
  • Android 10 (API nivel 29): Este fue un punto de inflexión crucial. A partir de Android 10, las aplicaciones que no son del sistema ya no pueden acceder a identificadores de dispositivo no reseteables como el IMEI, el número de serie del dispositivo o el MAC address (para WiFi y Bluetooth, se utilizan MAC addresses aleatorias). Incluso si una aplicación declara el permiso READ_PHONE_STATE y el usuario lo concede, los métodos que devuelven estos identificadores (como getDeviceId(), getSimSerialNumber(), getSubscriberId()) devolverán un valor nulo o un valor "placeholder" genérico (e.g., una cadena de ceros o un String vacío) en dispositivos con Android 10 o superior. Este cambio fue un paso audaz y necesario para reforzar la privacidad del usuario, impidiendo el rastreo persistente a través de identificadores de hardware.
  • Versiones posteriores: Android ha continuado refinando sus políticas de privacidad, siempre buscando dar más control al usuario y limitar la capacidad de las aplicaciones de recopilar datos sensibles sin justificación clara y consentimiento.

Permisos necesarios y su gestión

Para acceder a la información del teléfono, el permiso READ_PHONE_STATE es tradicionalmente el que se ha requerido. Puedes encontrar más información sobre este y otros permisos en la documentación de permisos de Android.

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Sin embargo, como ya mencionamos, para Android 10 y versiones superiores, este permiso ya no es suficiente para obtener el IMEI para aplicaciones de terceros. Solo las aplicaciones con permisos de sistema o las aplicaciones del fabricante del dispositivo (firmadas con la clave de la plataforma del sistema) pueden acceder a identificadores persistentes. El permiso READ_PRIVILEGED_PHONE_STATE existe, pero solo puede ser otorgado a aplicaciones preinstaladas o del sistema, no a aplicaciones de terceros que se descargan de Google Play.

La gestión de permisos en Kotlin implica solicitar al usuario en tiempo de ejecución:

import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {

    private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
            if (isGranted) {
                // Permiso concedido, ahora intenta obtener el IMEI (¡pero recuerda las limitaciones de Android 10+!)
                // Aunque para el IMEI ya no funcionará, es útil para otros datos relacionados con el teléfono si los permisos lo permiten.
            } else {
                // Permiso denegado, informar al usuario o deshabilitar la funcionalidad.
            }
        }

    private fun checkAndRequestPhoneStatePermission() {
        when {
            ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED -> {
                // Permiso ya concedido
            }
            shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) -> {
                // Mostrar una explicación al usuario de por qué necesita el permiso
                // y luego solicitarlo.
            }
            else -> {
                // Solicitar el permiso directamente
                requestPermissionLauncher.launch(Manifest.permission.READ_PHONE_STATE)
            }
        }
    }
}

A pesar de que el código anterior es el mecanismo correcto para solicitar el permiso, es crucial entender que obtener el IMEI con este permiso ya no es posible para la gran mayoría de las aplicaciones en Android 10 y superior. Esta es una limitación fundamental del sistema operativo y no un error en el código.

Obteniendo el Android ID con Kotlin

Mientras que el IMEI ha sido "blindado", el Android ID sigue siendo accesible para aplicaciones de terceros, aunque con sus propias particularidades y limitaciones que deben ser entendidas.

El método estándar y su implementación

Para obtener el Android ID, utilizamos la clase Settings.Secure. Este método es bastante directo:

import android.provider.Settings
import android.content.Context

fun getAndroidId(context: Context): String? {
    // No se requiere ningún permiso para acceder a Settings.Secure.ANDROID_ID
    val androidId = Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
    return androidId
}

// Ejemplo de uso en una actividad o fragmento:
// val myAndroidId = getAndroidId(this) // Si estás en una Activity
// Log.d("AndroidID", "El Android ID es: $myAndroidId")

Como se puede ver, la belleza de este método radica en su simplicidad: no requiere ningún permiso especial para acceder a él. Esto lo hace muy conveniente para propósitos internos de la aplicación.

Consideraciones sobre la unicidad y el "fingerprinting"

Aquí es donde la cosa se pone interesante y donde mi opinión como desarrollador entra en juego. Si bien el Android ID es un identificador relativamente estable para una aplicación dada en un dispositivo dado, no es universalmente persistente ni único para el dispositivo físico de la misma manera que el IMEI.

  • Restablecimiento de fábrica: Si el usuario realiza un restablecimiento de fábrica (factory reset), el Android ID cambiará.
  • Cambio de dispositivo: Naturalmente, si el usuario instala tu aplicación en un dispositivo nuevo, el Android ID será diferente.
  • Perfiles de trabajo/múltiples usuarios: En dispositivos con múltiples perfiles de usuario (como un perfil de trabajo o cuentas de invitados), cada perfil tendrá un Android ID diferente para tu aplicación.
  • Aplicaciones diferentes (en Android 8.0+): A partir de Android 8.0 (API nivel 26), el valor de Settings.Secure.ANDROID_ID es diferente para cada aplicación que lo solicita. Esto significa que si tu aplicación A y tu aplicación B están instaladas en el mismo dispositivo, obtendrán un Android ID diferente. Anteriormente, era el mismo para todas las aplicaciones del mismo fabricante o incluso todas las aplicaciones. Este cambio fue otra medida para evitar el "fingerprinting" entre aplicaciones y para proteger la privacidad del usuario.

Debido a estas limitaciones, el Android ID no debe ser utilizado para identificar de manera única a un usuario a largo plazo ni para construir perfiles que persistan más allá de una instalación de aplicación individual. Si necesitas una identificación persistente para tu usuario, deberías considerar un sistema de cuentas de usuario gestionado por tu propia aplicación (con un inicio de sesión, por ejemplo) o usar identificadores de instalación de servicios como Firebase. En mi experiencia, intentar forzar el uso del Android ID para propósitos de seguimiento de usuarios es una receta para la frustración y, lo que es más importante, una violación potencial de la privacidad del usuario. Es mucho más ético y compatible con las directrices de Google centrarse en identificadores específicos de la aplicación que el usuario pueda restablecer.

Desafíos al obtener el IMEI con Kotlin (y por qué no deberías intentarlo)

La insistencia en obtener el IMEI por parte de algunos desarrolladores es comprensible, dada su singularidad. Sin embargo, en el panorama actual de Android, no solo es difícil, sino que a menudo es contraproducente y puede llevar a la denegación de tu aplicación en la Google Play Store.

Restricciones de seguridad y Android 10+

Como se mencionó en la sección de privacidad, a partir de Android 10 (API nivel 29), el acceso a identificadores de dispositivo no reseteables como el IMEI está severamente restringido para las aplicaciones de terceros. Intentar utilizar TelephonyManager.getDeviceId() o TelephonyManager.getImei() en un dispositivo con Android 10 o superior, incluso con el permiso READ_PHONE_STATE concedido, devolverá un valor nulo o un SecurityException si la aplicación no tiene los permisos de sistema necesarios.

Esto no es un error ni un comportamiento inesperado; es una característica de seguridad fundamental diseñada para proteger la privacidad del usuario. Google ha sido muy claro al respecto en su documentación para desarrolladores. Las únicas aplicaciones que pueden acceder a estos identificadores son las aplicaciones del sistema (preinstaladas por el fabricante del dispositivo) o aquellas con privilegios especiales que son parte del firmware del sistema.

¿Quién puede obtener el IMEI y cómo?

Solo ciertas entidades tienen la capacidad de acceder al IMEI:

  • Aplicaciones del sistema o preinstaladas: Aquellas que vienen de fábrica con el dispositivo y que están firmadas con la clave de la plataforma del sistema. Tienen un conjunto de permisos más amplios, incluyendo READ_PRIVILEGED_PHONE_STATE.
  • Operadores de telefonía móvil: Utilizan el IMEI para identificar dispositivos en su red, activar servicios, bloquear teléfonos robados, etc. Esto se hace a nivel de red, no a través de una aplicación instalable por el usuario.
  • Fabricantes de dispositivos: Para fines de garantía, reparación y diagnóstico.

Para un desarrollador de una aplicación de terceros que distribuye a través de Google Play, el IMEI está efectivamente fuera de su alcance. Cualquier intento de eludir estas restricciones es probable que resulte en el rechazo de la aplicación en la tienda, o incluso en la suspensión de la cuenta de desarrollador, ya que Google toma muy en serio la violación de sus políticas para desarrolladores.

Alternativas para la identificación del dispositivo

Dada la imposibilidad de acceder al IMEI y las limitaciones del Android ID para el seguimiento persistente de usuarios, ¿qué alternativas existen para propósitos legítimos?

  1. Firebase Installation ID (FID): Si utilizas Firebase en tu aplicación, el Firebase Installation ID es un identificador único para cada instalación de la aplicación en un dispositivo. Para aprender a implementarlo, visita la documentación de Firebase Installation ID. Es estable durante la vida útil de la instalación de la aplicación, pero se restablece si la aplicación se desinstala y se vuelve a instalar. Es excelente para el análisis de aplicaciones y la segmentación de notificaciones push, ya que está diseñado para el ecosistema de Firebase. Es reseteable, lo cual es bueno para la privacidad.
  2. Identificadores publicitarios (Advertising ID): Disponible a través de la API de Google Play Services, el Advertising ID (también conocido como Google Play Services ID o GAID) es un identificador único, reseteable por el usuario, destinado específicamente para la publicidad personalizada y el análisis. Los usuarios pueden restablecer este ID en cualquier momento desde la configuración de Google de su dispositivo, lo que les da control sobre su privacidad. Es la alternativa recomendada por Google para casos de uso de publicidad. Más detalles pueden encontrarse en la documentación de Advertising ID de Google.
  3. UUIDs generados por la aplicación: Puedes generar un UUID (Universally Unique Identifier) aleatorio la primera vez que la aplicación se ejecuta y almacenarlo localmente (por ejemplo, en SharedPreferences o una base de datos local). Este ID será único para esa instalación de la aplicación y persistirá hasta que la aplicación sea desinstalada o sus datos borrados. Esto es ideal para identificar una instalación específica de la aplicación para propósitos internos, como mantener la configuración local o sesiones de usuario anónimas.

Mi consejo es siempre optar por una de estas alternativas reseteables y específicas para la aplicación, o mejor aún, implementar un sistema de autenticación de usuario si necesitas identificar a personas, no solo dispositivos. Esto no solo cumple con la

Diario Tecnología