¿Hay una identificación de dispositivo Android única?

¿Los dispositivos Android tienen una identificación única y, de ser así, cuál es una forma sencilla de acceder a ella utilizando Java?

Settings.Secure#ANDROID_ID devuelve el ID de Android como único para cada cadena hexadecimal de 64 bits del usuario .

 import android.provider.Settings.Secure; private String android_id = Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID); 

ACTUALIZACIÓN : a partir de las versiones recientes de Android, muchos de los problemas con ANDROID_ID se han resuelto, y creo que este enfoque ya no es necesario. Por favor, eche un vistazo a la respuesta de Anthony .

Divulgación completa: mi aplicación utilizó originalmente el enfoque siguiente pero ya no usa este enfoque, y ahora usamos el enfoque descrito en la entrada del Blog de Desarrolladores de Android que los enlaces de respuesta de emmby (es decir, generar y guardar un UUID#randomUUID() ).


Hay muchas respuestas a esta pregunta, la mayoría de las cuales solo funcionarán “algunas” veces, y desafortunadamente eso no es lo suficientemente bueno.

Basado en mis pruebas de dispositivos (todos los teléfonos, al menos uno de los cuales no está activado):

  1. Todos los dispositivos probados arrojaron un valor para TelephonyManager.getDeviceId()
  2. Todos los dispositivos GSM (todos probados con una SIM) devolvieron un valor para TelephonyManager.getSimSerialNumber()
  3. Todos los dispositivos CDMA devueltos null para getSimSerialNumber() (como se esperaba)
  4. Todos los dispositivos con una cuenta de Google agregada devolvieron un valor para ANDROID_ID
  5. Todos los dispositivos CDMA devolvieron el mismo valor (o derivación del mismo valor) para ANDROID_ID y TelephonyManager.getDeviceId() , siempre que se haya agregado una cuenta de Google durante la configuración.
  6. Todavía no tuve la oportunidad de probar dispositivos GSM sin tarjeta SIM, un dispositivo GSM sin cuenta de Google agregada, o cualquiera de los dispositivos en modo avión.

Por lo tanto, si desea algo exclusivo para el dispositivo en sí, TM.getDeviceId() debería ser suficiente. Obviamente, algunos usuarios son más paranoicos que otros, por lo que podría ser útil codificar uno o más de estos identificadores, de modo que la cadena siga siendo virtualmente única para el dispositivo, pero no identifique explícitamente el dispositivo real del usuario. Por ejemplo, usando String.hashCode() , combinado con un UUID:

 final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE); final String tmDevice, tmSerial, androidId; tmDevice = "" + tm.getDeviceId(); tmSerial = "" + tm.getSimSerialNumber(); androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode()); String deviceId = deviceUuid.toString(); 

podría dar como resultado algo así como: 00000000-54b3-e7c7-0000-000046bffd97

Funciona lo suficientemente bien para mí.

Como Richard menciona a continuación, no olvide que necesita permiso para leer las propiedades de TelephonyManager , así que agregue esto a su manifiesto:

  

importar libs

 import android.content.Context; import android.telephony.TelephonyManager; import android.view.View; 

Última actualización: 6/2/15


Después de leer todas las publicaciones de Stack Overflow sobre cómo crear una identificación única, el blog para desarrolladores de Google y la documentación de Android, siento que la “Pseudo ID” es la mejor opción posible.

Problema principal: Hardware vs Software

Hardware

  • Los usuarios pueden cambiar su hardware, tableta o teléfono Android, por lo que los ID únicos basados ​​en hardware no son buenas ideas para USUARIOS DE SEGUIMIENTO
  • Para el SEGUIMIENTO DE HARDWARE , esta es una gran idea

Software

  • Los usuarios pueden borrar / cambiar su ROM si están rooteados
  • Puede rastrear usuarios en todas las plataformas (iOS, Android, Windows y Web)
  • Lo mejor para SEGUIR UN USUARIO INDIVIDUAL con su consentimiento es simplemente hacer que inicien sesión (hacer esto sin problemas usando OAuth)

Desglose general con Android

– Garantía de exclusividad (incluye dispositivos rooteados) para API> = 9/10 (99.5% de dispositivos Android)

– Sin permisos extra

Código de Psuedo:

 if API >= 9/10: (99.5% of devices) return unique ID containing serial id (rooted devices may be different) else return unique ID of build information (may overlap data - API < 9) 

Gracias a @stansult por publicar todas nuestras opciones (en esta pregunta sobre desbordamiento de stack).

Lista de opciones - razones por las cuales / por qué no usarlas:

  • Correo electrónico del usuario - Software

    • El usuario podría cambiar el correo electrónico: ALTAMENTE improbable
    • API 5+ o
    • API 14+ ( Cómo obtener la dirección de correo electrónico principal del dispositivo Android )
  • Número de teléfono del usuario - Software

    • Los usuarios pueden cambiar los números de teléfono: ALTAMENTE improbable
  • IMEI - Hardware (solo teléfonos, necesita android.permission.READ_PHONE_STATE )

    • La mayoría de los usuarios odian el hecho de que dice "Llamadas telefónicas" en el permiso. Algunos usuarios dan malas calificaciones, porque creen que simplemente estás robando su información personal, cuando todo lo que realmente quieres hacer es rastrear las instalaciones de los dispositivos. Es obvio que estás recostackndo datos.
  • Android ID - Hardware (puede ser nulo, puede cambiar al restablecer la configuración de fábrica, puede modificarse en un dispositivo rooteado)

    • Como puede ser 'nulo', podemos verificar 'nulo' y cambiar su valor, pero esto significa que ya no será único.
    • Si tiene un usuario con un dispositivo de restablecimiento de fábrica, es posible que el valor haya cambiado o modificado en el dispositivo rooteado, por lo que puede haber entradas duplicadas si realiza un seguimiento de las instalaciones de los usuarios.
  • WLAN MAC Address - Hardware (necesita android.permission.ACCESS_WIFI_STATE )

    • Esta podría ser la segunda mejor opción, pero aún está recostackndo y almacenando un identificador único que proviene directamente de un usuario. Esto es obvio que estás recostackndo datos.
  • Dirección MAC Bluetooth - Hardware (dispositivos con Bluetooth, necesita android.permission.BLUETOOTH )

    • La mayoría de las aplicaciones en el mercado no usan Bluetooth, por lo que si su aplicación no usa Bluetooth y usted está incluyendo esto, el usuario podría sospechar.
  • ID de Pseudo-Unique - Software (para todos los dispositivos Android)

    • Muy posible, puede contener colisiones - ¡Vea mi método publicado a continuación!
    • Esto le permite tener una identificación 'casi única' del usuario sin tomar nada que sea privado. Puede crear su propia identificación anónima a partir de la información del dispositivo.

Sé que no hay una forma "perfecta" de obtener un ID único sin usar permisos; sin embargo, a veces solo necesitamos seguir la instalación del dispositivo. Cuando se trata de crear una ID única, podemos crear una 'identificación pseudo única' basada únicamente en la información que nos proporciona la API de Android sin usar permisos adicionales. De esta manera, podemos mostrar respeto al usuario e intentar ofrecer una buena experiencia de usuario también.

Con una identificación pseudo-única, realmente solo se topa con el hecho de que puede haber duplicados basados ​​en el hecho de que hay dispositivos similares. Puede ajustar el método combinado para hacerlo más único; sin embargo, algunos desarrolladores necesitan rastrear las instalaciones del dispositivo y esto hará el truco o el rendimiento basado en dispositivos similares.

API> = 9:

Si su dispositivo Android es API 9 o superior, se garantiza que será único debido al campo 'Build.SERIAL'.

RECUERDE , técnicamente solo se está perdiendo alrededor del 0.5% de los usuarios que tienen API <9 . Para que pueda centrarse en el resto: ¡Esto es el 99.5% de los usuarios!

API <9:

Si el dispositivo Android del usuario es inferior a API 9; con suerte, no han hecho un restablecimiento de fábrica y su 'Secure.ANDROID_ID' se conservará o no 'nulo'. (ver http://developer.android.com/about/dashboards/index.html )

Si todo lo demás falla:

Si todo lo demás falla, si el usuario tiene un API inferior a 9 (menor que Gingerbread), ha reiniciado su dispositivo o 'Secure.ANDROID_ID' devuelve 'nulo', entonces simplemente la ID devuelta estará basada únicamente en la información de su dispositivo Android. Aquí es donde pueden ocurrir las colisiones.

Cambios:

  • Se eliminó 'Android.SECURE_ID' debido a los restablecimientos de fábrica que podrían hacer que el valor cambie
  • Editado el código para cambiar en la API
  • Cambió el pseudo

Por favor, eche un vistazo al método a continuación:

 /** * Return pseudo unique ID * @return ID */ public static String getUniquePsuedoID() { // If all else fails, if the user does have lower than API 9 (lower // than Gingerbread), has reset their device or 'Secure.ANDROID_ID' // returns 'null', then simply the ID returned will be solely based // off their Android device information. This is where the collisions // can happen. // Thanks http://www.pocketmagic.net/?p=1662! // Try not to use DISPLAY, HOST or ID - these items could change. // If there are collisions, there will be overlapping data String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10); // Thanks to @Roman SL! // https://stackoverflow.com/a/4789483/950427 // Only devices with API >= 9 have android.os.Build.SERIAL // http://developer.android.com/reference/android/os/Build.html#SERIAL // If a user upgrades software or roots their device, there will be a duplicate entry String serial = null; try { serial = android.os.Build.class.getField("SERIAL").get(null).toString(); // Go ahead and return the serial for api => 9 return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString(); } catch (Exception exception) { // String needs to be initialized serial = "serial"; // some value } // Thanks @Joe! // https://stackoverflow.com/a/2853253/950427 // Finally, combine the values we have found by using the UUID class to create a unique identifier return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString(); } 

Nuevo (para aplicaciones con anuncios Y servicios de Google Play):

Desde la consola del desarrollador de Google Play:

A partir del 1 de agosto de 2014, la Política del Progtwig para Desarrolladores de Google Play requiere que todas las actualizaciones y cargas de aplicaciones nuevas usen el ID de publicidad en lugar de cualquier otro identificador persistente para fines publicitarios. Aprende más

Implementación :

Permiso:

  

Código:

 import com.google.android.gms.ads.identifier.AdvertisingIdClient; import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info; import com.google.android.gms.common.GooglePlayServicesAvailabilityException; import com.google.android.gms.common.GooglePlayServicesNotAvailableException; import java.io.IOException; ... // Do not call this function from the main thread. Otherwise, // an IllegalStateException will be thrown. public void getIdThread() { Info adInfo = null; try { adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext); } catch (IOException exception) { // Unrecoverable error connecting to Google Play services (eg, // the old version of the service doesn't support getting AdvertisingId). } catch (GooglePlayServicesAvailabilityException exception) { // Encountered a recoverable error connecting to Google Play services. } catch (GooglePlayServicesNotAvailableException exception) { // Google Play services is not available entirely. } final String id = adInfo.getId(); final boolean isLAT = adInfo.isLimitAdTrackingEnabled(); } 

Fuente / Documentos:

http://developer.android.com/google/play-services/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

Importante:

Se pretende que el ID de publicidad reemplace completamente el uso existente de otros identificadores con fines publicitarios (como el uso de ANDROID_ID en Settings.Secure) cuando Google Play Services esté disponible. Los casos en los que los Servicios de Google Play no están disponibles están indicados por una excepción GooglePlayServicesNotAvailableException lanzada por getAdvertisingIdInfo ().

Advertencia, los usuarios pueden restablecer:

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

Intenté hacer referencia a todos los enlaces de los que obtuve información. Si falta y necesita ser incluido, ¡por favor coméntelo!

ID de instancia de servicios de Google Player

https://developers.google.com/instance-id/

Como Dave Webb menciona, el Blog de Desarrolladores de Android tiene un artículo que cubre esto. Su solución preferida es rastrear instalaciones de aplicaciones en lugar de dispositivos, y eso funcionará bien para la mayoría de los casos de uso. La publicación del blog le mostrará el código necesario para que funcione, y le recomiendo que lo revise.

Sin embargo, la publicación del blog analiza las soluciones si necesita un identificador de dispositivo en lugar de un identificador de instalación de la aplicación. Hablé con alguien en Google para obtener una aclaración adicional sobre algunos artículos en caso de que necesite hacerlo. Esto es lo que descubrí sobre los identificadores de dispositivos que NO se mencionan en la publicación de blog mencionada anteriormente:

  • ANDROID_ID es el identificador de dispositivo preferido. ANDROID_ID es perfectamente confiable en las versiones de Android <= 2.1 o> = 2.3. Solo 2.2 tiene los problemas mencionados en la publicación.
  • Varios dispositivos de varios fabricantes se ven afectados por el error ANDROID_ID en 2.2.
  • Hasta donde he podido determinar, todos los dispositivos afectados tienen el mismo ANDROID_ID , que es 9774d56d682e549c . Que también es el mismo ID de dispositivo informado por el emulador, por cierto.
  • Google cree que los OEM han solucionado el problema para muchos o la mayoría de sus dispositivos, pero pude verificar que, al menos hasta principios de abril de 2011, todavía es bastante fácil encontrar dispositivos que tengan el ANDROID_ID dañado.

En base a las recomendaciones de Google, implementé una clase que generará un UUID único para cada dispositivo, usando ANDROID_ID como semilla, donde sea apropiado, recurriendo a TelephonyManager.getDeviceId () según sea necesario, y si eso falla, recurriendo a un UUID único generado al azar esto se mantiene en todos los reinicios de la aplicación (pero no en las reinstalaciones de la aplicación).

Tenga en cuenta que para los dispositivos que tienen que retroceder en la identificación del dispositivo, la ID única persistirá en los restablecimientos de fábrica. Esto es algo de lo que debes estar consciente. Si necesita asegurarse de que un restablecimiento de fábrica restablecerá su ID única, le recomendamos que recurra directamente al UUID aleatorio en lugar de a la ID del dispositivo.

Nuevamente, este código es para una ID de dispositivo, no una ID de instalación de aplicación. En la mayoría de las situaciones, una ID de instalación de la aplicación es probablemente lo que estás buscando. Pero si necesita una identificación de dispositivo, entonces el siguiente código probablemente funcione para usted.

 import android.content.Context; import android.content.SharedPreferences; import android.provider.Settings.Secure; import android.telephony.TelephonyManager; import java.io.UnsupportedEncodingException; import java.util.UUID; public class DeviceUuidFactory { protected static final String PREFS_FILE = "device_id.xml"; protected static final String PREFS_DEVICE_ID = "device_id"; protected volatile static UUID uuid; public DeviceUuidFactory(Context context) { if (uuid == null) { synchronized (DeviceUuidFactory.class) { if (uuid == null) { final SharedPreferences prefs = context .getSharedPreferences(PREFS_FILE, 0); final String id = prefs.getString(PREFS_DEVICE_ID, null); if (id != null) { // Use the ids previously computed and stored in the // prefs file uuid = UUID.fromString(id); } else { final String androidId = Secure.getString( context.getContentResolver(), Secure.ANDROID_ID); // Use the Android ID unless it's broken, in which case // fallback on deviceId, // unless it's not available, then fallback on a random // number which we store to a prefs file try { if (!"9774d56d682e549c".equals(androidId)) { uuid = UUID.nameUUIDFromBytes(androidId .getBytes("utf8")); } else { final String deviceId = ( (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE)) .getDeviceId(); uuid = deviceId != null ? UUID .nameUUIDFromBytes(deviceId .getBytes("utf8")) : UUID .randomUUID(); } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } // Write the value out to the prefs file prefs.edit() .putString(PREFS_DEVICE_ID, uuid.toString()) .commit(); } } } } } /** * Returns a unique UUID for the current android device. As with all UUIDs, * this unique ID is "very highly likely" to be unique across all Android * devices. Much more so than ANDROID_ID is. * * The UUID is generated by using ANDROID_ID as the base key if appropriate, * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to * be incorrect, and finally falling back on a random UUID that's persisted * to SharedPreferences if getDeviceID() does not return a usable value. * * In some rare circumstances, this ID may change. In particular, if the * device is factory reset a new device ID may be generated. In addition, if * a user upgrades their phone from certain buggy implementations of Android * 2.2 to a newer, non-buggy version of Android, the device ID may change. * Or, if a user uninstalls your app on a device that has neither a proper * Android ID nor a Device ID, this ID may change on reinstallation. * * Note that if the code falls back on using TelephonyManager.getDeviceId(), * the resulting ID will NOT change after a factory reset. Something to be * aware of. * * Works around a bug in Android 2.2 for many devices when using ANDROID_ID * directly. * * @see http://code.google.com/p/android/issues/detail?id=10603 * * @return a UUID that may be used to uniquely identify your device for most * purposes. */ public UUID getDeviceUuid() { return uuid; } } 

Aquí está el código que Reto Meier usó en la presentación de Google I / O este año para obtener una identificación única para el usuario:

 private static String uniqueID = null; private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID"; public synchronized static String id(Context context) { if (uniqueID == null) { SharedPreferences sharedPrefs = context.getSharedPreferences( PREF_UNIQUE_ID, Context.MODE_PRIVATE); uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null); if (uniqueID == null) { uniqueID = UUID.randomUUID().toString(); Editor editor = sharedPrefs.edit(); editor.putString(PREF_UNIQUE_ID, uniqueID); editor.commit(); } } return uniqueID; } 

Si combina esto con una estrategia de respaldo para enviar preferencias a la nube (también se describe en la charla de Reto, debe tener una identificación que se vincule con un usuario y se quede después de que el dispositivo se haya borrado, o incluso reemplazado. Planeo usar esto en análisis en el futuro (en otras palabras, todavía no he hecho eso :)).

También podría considerar la dirección MAC del adaptador de Wi-Fi. Obtenido así:

 WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE); return wm.getConnectionInfo().getMacAddress(); 

Requiere permiso android.permission.ACCESS_WIFI_STATE en el manifiesto.

Se informa que está disponible incluso cuando el Wi-Fi no está conectado. Si Joe de la respuesta anterior le prueba a este en sus muchos dispositivos, estaría bien.

En algunos dispositivos, no está disponible cuando Wi-Fi está desactivado.

NOTA: desde Android 6.x, devuelve una dirección mac falsa consistente: 02:00:00:00:00:00

Aquí hay información bastante útil.

Cubre cinco tipos de ID diferentes:

  1. IMEI (solo para dispositivos Android con uso del teléfono; necesita android.permission.READ_PHONE_STATE )
  2. ID de Pseudo-Unique (para todos los dispositivos Android)
  3. Android ID (puede ser nulo, puede cambiar al restablecer la configuración de fábrica, puede modificarse en el teléfono rooteado)
  4. WLAN MAC Dirección cadena (necesita android.permission.ACCESS_WIFI_STATE )
  5. BT cadena de dirección MAC (dispositivos con Bluetooth, necesita android.permission.BLUETOOTH )

El Blog oficial de Desarrolladores de Android ahora tiene un artículo completo sobre este mismo tema, Identificación de instalaciones de aplicaciones .

En Google I / O, Reto Meier dio a conocer una sólida respuesta a cómo abordar esto, que debería cumplir con la mayoría de los desarrolladores, para rastrear a los usuarios a través de las instalaciones. Anthony Nolan muestra la dirección en su respuesta, pero pensé que escribiría el enfoque completo para que otros puedan ver cómo hacerlo (me tomó un tiempo encontrar los detalles).

Este enfoque le dará una identificación de usuario segura y anónima que será persistente para el usuario en diferentes dispositivos (en función de la cuenta principal de Google) y en todas las instalaciones. El enfoque básico es generar un ID de usuario aleatorio y almacenarlo en las preferencias compartidas de las aplicaciones. A continuación, utiliza el agente de copia de seguridad de Google para almacenar las preferencias compartidas vinculadas a la cuenta de Google en la nube.

Veamos el enfoque completo. Primero, necesitamos crear una copia de seguridad para nuestras Preferencias Compartidas usando el Servicio de Copia de Seguridad de Android. Comience por registrar su aplicación a través de http://developer.android.com/google/backup/signup.html .

Google le dará una clave de servicio de respaldo que debe agregar al manifiesto. También necesita decirle a la aplicación que use BackupAgent de la siguiente manera:

  ...   

Luego debe crear el agente de respaldo y decirle que use el agente auxiliar para las preferencias compartidas:

 public class MyBackupAgent extends BackupAgentHelper { // The name of the SharedPreferences file static final String PREFS = "user_preferences"; // A key to uniquely identify the set of backup data static final String PREFS_BACKUP_KEY = "prefs"; // Allocate a helper and add it to the backup agent @Override public void onCreate() { SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS); addHelper(PREFS_BACKUP_KEY, helper); } } 

Para completar la copia de seguridad, debe crear una instancia de BackupManager en su actividad principal:

 BackupManager backupManager = new BackupManager(context); 

Finalmente, cree una ID de usuario, si aún no existe, y almacénela en SharedPreferences:

  public static String getUserID(Context context) { private static String uniqueID = null; private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID"; if (uniqueID == null) { SharedPreferences sharedPrefs = context.getSharedPreferences( MyBackupAgent.PREFS, Context.MODE_PRIVATE); uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null); if (uniqueID == null) { uniqueID = UUID.randomUUID().toString(); Editor editor = sharedPrefs.edit(); editor.putString(PREF_UNIQUE_ID, uniqueID); editor.commit(); //backup the changes BackupManager mBackupManager = new BackupManager(context); mBackupManager.dataChanged(); } } return uniqueID; } 

This User_ID will now be persistent across installations, even if the user moves device.

For more information on this approach see Reto’s talk .

And for full details of how to implement the backup agent see Data Backup . I particularly recommend the section at the bottom on testing as the backup does not happen instantaneously and so to test you have to force the backup.

The following code returns the device serial number using a hidden Android API. But, this code don’t works on Samsung Galaxy Tab because “ro.serialno” isn’t set on this device.

 String serial = null; try { Class c = Class.forName("android.os.SystemProperties"); Method get = c.getMethod("get", String.class); serial = (String) get.invoke(c, "ro.serialno"); } catch (Exception ignored) { } 

I think this is sure fire way of building a skeleton for a unique ID… check it out.

Pseudo-Unique ID, that works on all Android devices Some devices don’t have a phone (eg. Tablets) or for some reason, you don’t want to include the READ_PHONE_STATE permission. You can still read details like ROM Version, Manufacturer name, CPU type, and other hardware details, that will be well suited if you want to use the ID for a serial key check, or other general purposes. The ID computed in this way won’t be unique: it is possible to find two devices with the same ID (based on the same hardware and ROM image) but the changes in real-world applications are negligible. For this purpose you can use the Build class:

 String m_szDevIDShort = "35" + //we make this look like a valid IMEI Build.BOARD.length()%10+ Build.BRAND.length()%10 + Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 + Build.DISPLAY.length()%10 + Build.HOST.length()%10 + Build.ID.length()%10 + Build.MANUFACTURER.length()%10 + Build.MODEL.length()%10 + Build.PRODUCT.length()%10 + Build.TAGS.length()%10 + Build.TYPE.length()%10 + Build.USER.length()%10 ; //13 digits 

Most of the Build members are strings, what we’re doing here is to take their length and transform it via modulo in a digit. We have 13 such digits and we are adding two more in front (35) to have the same size ID as the IMEI (15 digits). There are other possibilities here are well, just have a look at these strings. Returns something like 355715565309247 . No special permission is required, making this approach very convenient.


(Extra info: The technique given above was copied from an article on Pocket Magic .)

Using the code below, you can get the unique device ID of an Android OS device as a string.

 deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

A Serial field was added to the Build class in API level 9 (Android 2.3 – Gingerbread). Documentation says it represents the hardware serial number. Thus it should be unique, if it exists on the device.

I don’t know whether it is actually supported (=not null) by all devices with API level >= 9 though.

One thing I’ll add – I have one of those unique situations.

Utilizando:

 deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.ANDROID_ID); 

Turns out that even though my Viewsonic G Tablet reports a DeviceID that is not Null, every single G Tablet reports the same number.

Makes it interesting playing “Pocket Empires” which gives you instant access to someone’s account based on the “unique” DeviceID.

My device does not have a cell radio.

For detailed instructions on how to get a unique identifier for each Android device your application is installed from, see the official Android Developers Blog posting Identifying App Installations .

It seems the best way is for you to generate one yourself upon installation and subsequently read it when the application is re-launched.

I personally find this acceptable but not ideal. No one identifier provided by Android works in all instances as most are dependent on the phone’s radio states (Wi-Fi on/off, cellular on/off, Bluetooth on/off). The others, like Settings.Secure.ANDROID_ID must be implemented by the manufacturer and are not guaranteed to be unique.

The following is an example of writing data to an installation file that would be stored along with any other data the application saves locally.

 public class Installation { private static String sID = null; private static final String INSTALLATION = "INSTALLATION"; public synchronized static String id(Context context) { if (sID == null) { File installation = new File(context.getFilesDir(), INSTALLATION); try { if (!installation.exists()) writeInstallationFile(installation); sID = readInstallationFile(installation); } catch (Exception e) { throw new RuntimeException(e); } } return sID; } private static String readInstallationFile(File installation) throws IOException { RandomAccessFile f = new RandomAccessFile(installation, "r"); byte[] bytes = new byte[(int) f.length()]; f.readFully(bytes); f.close(); return new String(bytes); } private static void writeInstallationFile(File installation) throws IOException { FileOutputStream out = new FileOutputStream(installation); String id = UUID.randomUUID().toString(); out.write(id.getBytes()); out.close(); } } 

Add Below code in class file:

 final TelephonyManager tm = (TelephonyManager) getBaseContext() .getSystemService(SplashActivity.TELEPHONY_SERVICE); final String tmDevice, tmSerial, androidId; tmDevice = "" + tm.getDeviceId(); Log.v("DeviceIMEI", "" + tmDevice); tmSerial = "" + tm.getSimSerialNumber(); Log.v("GSM devices Serial Number[simcard] ", "" + tmSerial); androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); Log.v("androidId CDMA devices", "" + androidId); UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode()); String deviceId = deviceUuid.toString(); Log.v("deviceIdUUID universally unique identifier", "" + deviceId); String deviceModelName = android.os.Build.MODEL; Log.v("Model Name", "" + deviceModelName); String deviceUSER = android.os.Build.USER; Log.v("Name USER", "" + deviceUSER); String devicePRODUCT = android.os.Build.PRODUCT; Log.v("PRODUCT", "" + devicePRODUCT); String deviceHARDWARE = android.os.Build.HARDWARE; Log.v("HARDWARE", "" + deviceHARDWARE); String deviceBRAND = android.os.Build.BRAND; Log.v("BRAND", "" + deviceBRAND); String myVersion = android.os.Build.VERSION.RELEASE; Log.v("VERSION.RELEASE", "" + myVersion); int sdkVersion = android.os.Build.VERSION.SDK_INT; Log.v("VERSION.SDK_INT", "" + sdkVersion); 

Add in AndroidManifest.xml:

  

The unique device ID of an Android OS device as String, using TelephonyManager and ANDROID_ID , is obtained by:

 String deviceId; final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if (mTelephony.getDeviceId() != null) { deviceId = mTelephony.getDeviceId(); } else { deviceId = Secure.getString( getApplicationContext().getContentResolver(), Secure.ANDROID_ID); } 

But I strongly recommend a method suggested by Google, see Identifying App Installations .

There are a lot of different approaches to work around those ANDROID_ID issues (may be null sometimes or devices of a specific model always return the same ID) with pros and cons:

  • Implementing a custom ID generation algorithm (based on device properties that are supposed to be static and won’t change -> who knows)
  • Abusing other IDs like IMEI , serial number, Wi-Fi/Bluetooth-MAC address (they won’t exist on all devices or additional permissions become necessary)

I myself prefer using an existing OpenUDID implementation (see https://github.com/ylechelle/OpenUDID ) for Android (see https://github.com/vieux/OpenUDID ). It is easy to integrate and makes use of the ANDROID_ID with fallbacks for those issues mentioned above.

How about the IMEI . That is unique for Android or other mobile devices.

My two cents – NB this is for a device (err) unique ID – not the installation one as discussed in the Android developers’s blog .

Of note that the solution provided by @emmby falls back in a per application ID as the SharedPreferences are not synchronized across processes (see here and here ). So I avoided this altogether.

Instead, I encapsulated the various strategies for getting a (device) ID in an enum – changing the order of the enum constants affects the priority of the various ways of getting the ID. The first non-null ID is returned or an exception is thrown (as per good Java practices of not giving null a meaning). So for instance I have the TELEPHONY one first – but a good default choice would be the ANDROID_ID beta:

 import android.Manifest.permission; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.pm.PackageManager; import android.net.wifi.WifiManager; import android.provider.Settings.Secure; import android.telephony.TelephonyManager; import android.util.Log; // TODO : hash public final class DeviceIdentifier { private DeviceIdentifier() {} /** @see http://code.google.com/p/android/issues/detail?id=10603 */ private static final String ANDROID_ID_BUG_MSG = "The device suffers from " + "the Android ID bug - its ID is the emulator ID : " + IDs.BUGGY_ANDROID_ID; private static volatile String uuid; // volatile needed - see EJ item 71 // need lazy initialization to get a context /** * Returns a unique identifier for this device. The first (in the order the * enums constants as defined in the IDs enum) non null identifier is * returned or a DeviceIDException is thrown. A DeviceIDException is also * thrown if ignoreBuggyAndroidID is false and the device has the Android ID * bug * * @param ctx * an Android constant (to retrieve system services) * @param ignoreBuggyAndroidID * if false, on a device with the android ID bug, the buggy * android ID is not returned instead a DeviceIDException is * thrown * @return a *device* ID - null is never returned, instead a * DeviceIDException is thrown * @throws DeviceIDException * if none of the enum methods manages to return a device ID */ public static String getDeviceIdentifier(Context ctx, boolean ignoreBuggyAndroidID) throws DeviceIDException { String result = uuid; if (result == null) { synchronized (DeviceIdentifier.class) { result = uuid; if (result == null) { for (IDs id : IDs.values()) { try { result = uuid = id.getId(ctx); } catch (DeviceIDNotUniqueException e) { if (!ignoreBuggyAndroidID) throw new DeviceIDException(e); } if (result != null) return result; } throw new DeviceIDException(); } } } return result; } private static enum IDs { TELEPHONY_ID { @Override String getId(Context ctx) { // TODO : add a SIM based mechanism ? tm.getSimSerialNumber(); final TelephonyManager tm = (TelephonyManager) ctx .getSystemService(Context.TELEPHONY_SERVICE); if (tm == null) { w("Telephony Manager not available"); return null; } assertPermission(ctx, permission.READ_PHONE_STATE); return tm.getDeviceId(); } }, ANDROID_ID { @Override String getId(Context ctx) throws DeviceIDException { // no permission needed ! final String andoidId = Secure.getString( ctx.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); if (BUGGY_ANDROID_ID.equals(andoidId)) { e(ANDROID_ID_BUG_MSG); throw new DeviceIDNotUniqueException(); } return andoidId; } }, WIFI_MAC { @Override String getId(Context ctx) { WifiManager wm = (WifiManager) ctx .getSystemService(Context.WIFI_SERVICE); if (wm == null) { w("Wifi Manager not available"); return null; } assertPermission(ctx, permission.ACCESS_WIFI_STATE); // I guess // getMacAddress() has no java doc !!! return wm.getConnectionInfo().getMacAddress(); } }, BLUETOOTH_MAC { @Override String getId(Context ctx) { BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter(); if (ba == null) { w("Bluetooth Adapter not available"); return null; } assertPermission(ctx, permission.BLUETOOTH); return ba.getAddress(); } } // TODO PSEUDO_ID // http://www.pocketmagic.net/2011/02/android-unique-device-id/ ; static final String BUGGY_ANDROID_ID = "9774d56d682e549c"; private final static String TAG = IDs.class.getSimpleName(); abstract String getId(Context ctx) throws DeviceIDException; private static void w(String msg) { Log.w(TAG, msg); } private static void e(String msg) { Log.e(TAG, msg); } } private static void assertPermission(Context ctx, String perm) { final int checkPermission = ctx.getPackageManager().checkPermission( perm, ctx.getPackageName()); if (checkPermission != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Permission " + perm + " is required"); } } // ========================================================================= // Exceptions // ========================================================================= public static class DeviceIDException extends Exception { private static final long serialVersionUID = -8083699995384519417L; private static final String NO_ANDROID_ID = "Could not retrieve a " + "device ID"; public DeviceIDException(Throwable throwable) { super(NO_ANDROID_ID, throwable); } public DeviceIDException(String detailMessage) { super(detailMessage); } public DeviceIDException() { super(NO_ANDROID_ID); } } public static final class DeviceIDNotUniqueException extends DeviceIDException { private static final long serialVersionUID = -8940090896069484955L; public DeviceIDNotUniqueException() { super(ANDROID_ID_BUG_MSG); } } } 

Here is how I am generating the unique id:

 public static String getDeviceId(Context ctx) { TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE); String tmDevice = tm.getDeviceId(); String androidId = Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID); String serial = null; if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) serial = Build.SERIAL; if(tmDevice != null) return "01" + tmDevice; if(androidId != null) return "02" + androidId; if(serial != null) return "03" + serial; // other alternatives (ie Wi-Fi MAC, Bluetooth MAC, etc.) return null; } 

Another way is to use /sys/class/android_usb/android0/iSerial in an app without any permissions whatsoever.

 user@creep:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial -rw-r--r-- root root 4096 2013-01-10 21:08 iSerial user@creep:~$ adb shell cat /sys/class/android_usb/android0/iSerial 0A3CXXXXXXXXXX5 

To do this in Java one would just use a FileInputStream to open the iSerial file and read out the characters. Just be sure you wrap it in an exception handler, because not all devices have this file.

At least the following devices are known to have this file world-readable:

  • Galaxy Nexus
  • Nexus S
  • Motorola Xoom 3G
  • Toshiba AT300
  • HTC One V
  • Mini MK802
  • Samsung Galaxy S II

You can also see my blog post Leaking Android hardware serial number to unprivileged apps where I discuss what other files are available for information.

For hardware recognition of a specific Android device you could check the MAC Addresses.

you can do it that way:

en AndroidManifest.xml

now in your code:

 List interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces()); for (NetworkInterface interface : interfacesList) { // This will give you the interface MAC ADDRESS interface.getHardwareAddress(); } 

In every Android device their is at least a “wlan0” Interface witch is the WI-FI chip. This code works even when WI-FI is not turned on.

PS Their are a bunch of other Interfaces you will get from the list containing MACS But this can change between phones.

I use the following code to get the IMEI or use Secure. ANDROID_ID as an alternative, when the device doesn’t have phone capabilities:

 String identifier = null; TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)); if (tm != null) identifier = tm.getDeviceId(); if (identifier == null || identifier .length() == 0) identifier = Secure.getString(activity.getContentResolver(),Secure.ANDROID_ID); 

More specifically, Settings.Secure.ANDROID_ID . This is a 64-bit quantity that is generated and stored when the device first boots. It is reset when the device is wiped.

ANDROID_ID seems a good choice for a unique device identifier. There are downsides: First, it is not 100% reliable on releases of Android prior to 2.2 (“Froyo”). Also, there has been at least one widely-observed bug in a popular handset from a major manufacturer, where every instance has the same ANDROID_ID.

Google Instance ID

Released at I/O 2015; on Android requires play services 7.5.

https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation

 InstanceID iid = InstanceID.getInstance( context ); // Google docs are wrong - this requires context String id = iid.getId(); // blocking call 

It seems that Google intends for this ID to be used to identify installations across Android, Chrome, and iOS.

It identifies an installation rather then a device, but then again, ANDROID_ID (which is the accepted answer) now no longer identifies devices either. With the ARC runtime a new ANDROID_ID is generated for every installation ( details here ), just like this new instance ID. Also, I think that identifying installations (not devices) is what most of us are actually looking for.

The advantages of instance ID

It appears to me that Google intends for it to be used for this purpose (identifying your installations), it is cross-platform, and can be used for a number of other purposes (see the links above).

If you use GCM, then you will eventually need to use this instance ID because you need it in order to get the GCM token (which replaces the old GCM registration ID).

The disadvantages/issues

In the current implementation (GPS 7.5) the instance ID is retrieved from a server when your app requests it. This means that the call above is a blocking call – in my unscientific testing it takes 1-3 seconds if the device is online, and 0.5 – 1.0 seconds if off-line (presumbly this is how long it waits before giving up and generating a random ID). This was tested in North America on Nexus 5 with Android 5.1.1 and GPS 7.5.

If you use the ID for the purposes they intend – eg. app authentication, app identification, GCM – I think this 1-3 seconds could be a nuisance (depending on your app, of course).

Android device mac id also a unique id, it won’t change suppose if we format the device itself so using the following code to get mac id

 WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE); WifiInfo info = manager.getConnectionInfo(); String address = info.getMacAddress(); 

Also do not forget to add the appropriate permissions into your AndroidManifest.xml

  

There are 30+ answers here and some are same and some are unique. This answer is based on few of those answers. One of them being @Lenn Dolling’s answer.

It combines 3 IDs and creates a 32-digit hex string. It has worked very well for me.

3 IDs are:
Pseudo-ID – It is generated based on physical device specifications
ANDROID_IDSettings.Secure.ANDROID_ID
Bluetooth Address – Bluetooth adapter address

It will return something like this: 551F27C060712A72730B0A0F734064B1

Note: You can always add more IDs to the longId string. For example, Serial #. wifi adapter address. IMEI. This way you are making it more unique per device.

 @SuppressWarnings("deprecation") @SuppressLint("HardwareIds") public static String generateDeviceIdentifier(Context context) { String pseudoId = "35" + Build.BOARD.length() % 10 + Build.BRAND.length() % 10 + Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 + Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 + Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 + Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 + Build.TAGS.length() % 10 + Build.TYPE.length() % 10 + Build.USER.length() % 10; String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); String btId = ""; if (bluetoothAdapter != null) { btId = bluetoothAdapter.getAddress(); } String longId = pseudoId + androidId + btId; try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); messageDigest.update(longId.getBytes(), 0, longId.length()); // get md5 bytes byte md5Bytes[] = messageDigest.digest(); // creating a hex string String identifier = ""; for (byte md5Byte : md5Bytes) { int b = (0xFF & md5Byte); // if it is a single digit, make sure it have 0 in front (proper padding) if (b <= 0xF) { identifier += "0"; } // add number to string identifier += Integer.toHexString(b); } // hex string to uppercase identifier = identifier.toUpperCase(); return identifier; } catch (Exception e) { Log.e("TAG", e.toString()); } return ""; } 

Google now has an Advertising ID .
This can also be used, but note that :

The advertising ID is a user-specific, unique, resettable ID

y

enables users to reset their identifier or opt out of interest-based ads within Google Play apps.

So though this id may change, it seems that soon we may not have a choice , depends on the purpose of this id.

More info @ develper.android

Copy-paste code here

HTH

TelephonyManger.getDeviceId() Returns the unique device ID, for example, the IMEI for GSM and the MEID or ESN for CDMA phones.

 final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); String myAndroidDeviceId = mTelephony.getDeviceId(); 

But i recommend to use:

Settings.Secure.ANDROID_ID that returns the Android ID as an unique 64-bit hex string.

  String myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

Sometimes TelephonyManger.getDeviceId() will return null, so to assure an unique id you will use this method:

 public String getUniqueID(){ String myAndroidDeviceId = ""; TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if (mTelephony.getDeviceId() != null){ myAndroidDeviceId = mTelephony.getDeviceId(); }else{ myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); } return myAndroidDeviceId; }