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

Respuestas:

2026

Settings.Secure#ANDROID_IDdevuelve la ID de Android como única para cada usuario de una cadena hexadecimal de 64 bits.

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID); 
Anthony Forloney
fuente
477
A veces se sabe que es nulo, está documentado como "puede cambiar al restablecer los valores de fábrica". Use bajo su propio riesgo, y puede cambiarse fácilmente en un teléfono rooteado.
Seva Alekseyev
18
Creo que debemos tener cuidado al usar ANDROID_ID en el hash en la primera respuesta, porque puede que no se configure cuando la aplicación se ejecuta por primera vez, se puede configurar más tarde o incluso puede cambiar en teoría, por lo tanto, la identificación única puede cambiar
46
Tenga en cuenta que existen grandes limitaciones con esta solución: android-developers.blogspot.com/2011/03/…
emmby
35
ANDROID_ID ya no identifica de forma exclusiva un dispositivo (a partir de 4.2): stackoverflow.com/a/13465373/150016
Tom
1146

ACTUALIZACIÓN : a partir de versiones recientes de Android, muchos de los problemas ANDROID_IDse 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 usó originalmente el siguiente enfoque, pero ya no usa este enfoque, y ahora usamos el enfoque descrito en la entrada del Blog para desarrolladores de Android a la que los enlaces de respuesta de emmby (es decir, generar y guardar a 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.

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

  1. Todos los dispositivos probados devolvieron 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 como nulos 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 ambos ANDROID_IDy TelephonyManager.getDeviceId(), siempre y cuando se haya agregado una cuenta de Google durante la configuración.
  6. Todavía no tuve la oportunidad de probar dispositivos GSM sin SIM, un dispositivo GSM sin cuenta de Google agregada o ninguno de los dispositivos en modo avión.

Entonces, si desea algo único para el dispositivo en sí, TM.getDeviceId() debería ser suficiente. Obviamente, algunos usuarios son más paranoicos que otros, por lo que puede ser útil hacer hash 1 o más de estos identificadores, para que la cadena siga siendo prácticamente exclusiva del 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 resultar en algo como: 00000000-54b3-e7c7-0000-000046bffd97

Funciona bastante bien para mí.

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

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

importar libs

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;
Joe
fuente
151
La identificación basada en telefonía no estará disponible en tabletas, ¿no?
Seva Alekseyev
22
Por eso dije que la mayoría no funcionará todo el tiempo :) Todavía no he visto ninguna respuesta a esta pregunta que sea confiable para todos los dispositivos, todos los tipos de dispositivos y todas las configuraciones de hardware. Es por eso que esta pregunta está aquí para empezar. Está bastante claro que no hay una solución final para todo esto. Los fabricantes de dispositivos individuales pueden tener números de serie de dispositivos, pero no están expuestos para que los usemos, y no es un requisito. Por lo tanto, nos queda lo que está disponible para nosotros.
Joe
31
El código de muestra funciona muy bien. Recuerde agregar <uses-permission android:name="android.permission.READ_PHONE_STATE" />al archivo de manifiesto. Si se almacena en una base de datos, la cadena devuelta tiene 36 caracteres de longitud.
Richard
10
Tenga en cuenta que existen grandes limitaciones con esta solución: android-developers.blogspot.com/2011/03/…
emmby
18
@softarn: Creo que a lo que te refieres es al Blog para desarrolladores de Android al que ya está vinculado emmby, que explica lo que estás tratando de decir, por lo que tal vez deberías haber votado simplemente por su comentario. De cualquier manera, como emmby menciona en su respuesta, todavía hay problemas incluso con la información del blog. La pregunta solicita un identificador de DISPOSITIVO único (no un identificador de instalación), por lo que no estoy de acuerdo con su declaración. El blog asume que lo que desea no es necesariamente rastrear el dispositivo, mientras que la pregunta es solo eso. Estoy de acuerdo con el blog de lo contrario.
Joe
439

Última actualización: 6/2/15


Después de leer cada publicación de Stack Overflow sobre la creación de una ID ú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 las ID únicas basadas en hardware no son buenas ideas para SEGUIR A LOS USUARIOS
  • Para TRACKING HARDWARE , esta es una gran idea

Software

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

Desglose general con Android

- Garantizar la unicidad (incluir dispositivos rooteados) para API> = 9/10 (99.5% de dispositivos Android)

- Sin permisos adicionales

Código Psuedo:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return the unique ID of build information (may overlap data - API < 9)

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

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

  • Correo electrónico del usuario - Software

  • Número de teléfono del usuario - Software

    • Los usuarios pueden cambiar los números de teléfono - ALTAMENTE improbable
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Hardware (solo teléfonos, necesidades 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 del dispositivo. Es obvio que está recopilando datos.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • ID de Android: hardware (puede ser nulo, puede cambiar con el restablecimiento de fábrica, puede modificarse en un dispositivo rooteado)

    • Como puede ser 'nulo', podemos verificar si es '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, el valor puede haber cambiado o alterado en el dispositivo rooteado, por lo que puede haber entradas duplicadas si está rastreando las instalaciones del usuario.
  • Dirección MAC de WLAN - Hardware (necesidades android.permission.ACCESS_WIFI_STATE)

    • Esta podría ser la segunda mejor opción, pero aún está recopilando y almacenando un identificador único que proviene directamente de un usuario. Esto es obvio que está recopilando datos.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Dirección MAC de Bluetooth: hardware (dispositivos con Bluetooth, necesidades 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 lo incluye, el usuario podría sospechar.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • ID pseudounica: 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 ninguna forma 'perfecta' de obtener una identificación única sin usar permisos; sin embargo, a veces solo necesitamos rastrear la instalación del dispositivo. Cuando se trata de crear una identificación única, podemos crear una 'identificación pseudo única' basada únicamente en la información que la API de Android nos brinda sin usar permisos adicionales. De esta forma, podemos mostrar respeto al usuario e intentar ofrecer una buena experiencia de usuario también.

Con una identificación pseudo-única, realmente solo te encuentras 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 exclusivo; sin embargo, algunos desarrolladores necesitan rastrear las instalaciones de dispositivos y esto hará el truco o el rendimiento en función de 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 concentrarse en el resto: ¡esto es el 99.5% de los usuarios!

API <9:

Si el dispositivo Android del usuario es inferior a la 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 valor inferior a API 9 (inferior a Gingerbread), ha reiniciado su dispositivo o 'Secure.ANDROID_ID' devuelve 'nulo', entonces el ID devuelto se basará únicamente en la información de su dispositivo Android. Aquí es donde pueden ocurrir las colisiones.

Cambios:

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

Por favor, eche un vistazo al siguiente método:

/**
 * 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 programa para desarrolladores de Google Play requiere que todas las nuevas cargas y actualizaciones de aplicaciones utilicen el ID de publicidad en lugar de cualquier otro identificador persistente para fines publicitarios. Aprende más

implementación :

Permiso:

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

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 (e.g.,
    // 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 por completo el uso existente de otros identificadores para 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 se indican mediante una excepción GooglePlayServicesNotAvailableException lanzada por getAdvertisingIdInfo ().

Advertencia, los usuarios pueden restablecer:

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

He tratado de hacer referencia a cada enlace del que tomé información. Si falta y necesita ser incluido, ¡por favor comente!

ID de instancia de Google Player Services

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

Jared Burrows
fuente
Pero, ¿no cambiaría la Buildclase con la actualización del sistema operativo? ¿Especialmente si la API se actualizó? Si es así, ¿cómo garantiza que esto sea único? (Hablando sobre el método que escribió)
LuckyMe
2
Utilicé tu método en mi aplicación para enviar comentarios. tengo malas noticias. Desafortunadamente, PsuedoID no es único por completo. mi servidor registró más de 100 por 5 ID y más de 30 por casi 30 ID. los ID más repetidos son 'ffffffff-fc8f-6093-ffff-ffffd8' (159 registros) y 'ffffffff-fe99-b334-ffff-ffffef' (154 veces). También basado en el tiempo y los comentarios es obvio que hay diferentes personas. el total de registros hasta ahora es de 10,000. por favor, hágame saber por qué sucedió esto. tanques
hojjat reyhane
1
Escribí esto hace más de 1.5 años. No estoy seguro de por qué no es exclusivo para ti. Puedes probar la identificación de publicidad. De lo contrario, puede encontrar su propia solución.
Jared Burrows
2
realmente apreciaría mucho si lees la pregunta y piensas sobre esto
Durai Amuthan. H
1
@ user1587329 Gracias. Estoy tratando de mantener esto actualizado para todos. Esta pregunta es complicada cuando se trata de hardware vs software y multiplataforma.
Jared Burrows
340

Como Dave Webb menciona, el Blog para desarrolladores de Android tiene un artículo que cubre esto. Su solución preferida es rastrear las instalaciones de aplicaciones en lugar de los 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 continúa discutiendo 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 algunas aclaraciones adicionales sobre algunos elementos 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 la misma identificación de dispositivo informada 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 a principios de abril de 2011, al menos, todavía es bastante fácil encontrar dispositivos que tengan el ANDROID_ID roto.

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

Tenga en cuenta que para los dispositivos que han de repliegue en el identificador de dispositivo, el ID único SE persistir a través de reinicios de fábrica. Esto es algo a tener en cuenta. Si necesita asegurarse de que un restablecimiento de fábrica restablecerá su ID única, puede considerar recurrir directamente al UUID aleatorio en lugar de la ID del dispositivo.

Nuevamente, este código es para una ID de dispositivo, no para una ID de instalación de aplicación. Para la mayoría de las situaciones, una identificación de instalación de la aplicación es probablemente lo que está buscando. Pero si necesita una ID de dispositivo, entonces el siguiente código probablemente funcionará 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;
    }
}
emmby
fuente
66
¿No deberías estar troceando las diferentes ID para que todas sean del mismo tamaño? Además, debe codificar la ID del dispositivo para no exponer accidentalmente información privada.
Steve Pomeroy
2
Buenos puntos, Steve. Actualicé el código para devolver siempre un UUID. Esto garantiza que a) las ID generadas sean siempre del mismo tamaño, yb) las ID de Android y dispositivos se procesen antes de ser devueltas para evitar la exposición accidental de información personal. También actualicé la descripción para tener en cuenta que la ID del dispositivo persistirá en todos los restablecimientos de fábrica y que esto puede no ser deseable para algunos usuarios.
emmby
1
Creo que eres incorrecto; la solución preferida es rastrear instalaciones, no identificadores de dispositivos. Su código es sustancialmente más largo y más complejo que eso en la publicación del blog y no es obvio para mí que agregue algún valor.
Tim Bray
77
Buen punto, actualicé el comentario para sugerir encarecidamente a los usuarios que utilicen identificadores de instalación de aplicaciones en lugar de identificadores de dispositivo. Sin embargo, creo que esta solución sigue siendo valiosa para las personas que necesitan un dispositivo en lugar de la ID de instalación.
emmby
8
ANDROID_ID puede cambiar en el restablecimiento de fábrica, por lo que no puede identificar dispositivos también
Samuel
180

Aquí está el código que Reto Meier usó en la presentación de E / S de Google 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 copia de seguridad para enviar preferencias a la nube (también se describe en la charla de Reto , debe tener una identificación que se vincule a un usuario y permanezca después de que el dispositivo haya sido borrado, o incluso reemplazado. Planeo usar esto en análisis en el futuro (en otras palabras, aún no he hecho eso :).

Anthony Nolan
fuente
Estaba usando el método de @Lenn Dolling con la hora actual añadida para una identificación única. Pero esto parece una forma más simple y confiable. Gracias Reto Meier y Antony Nolan
Gökhan Barış Aker
Es genial, pero ¿qué pasa con los dispositivos rooteados? Pueden acceder a esto y cambiar de uid a uno diferente fácilmente.
tasomaniac
3
Excelente opción si no necesita la identificación única para persistir después de una desinstalación y reinstalación (por ejemplo, evento / juego promocional donde tiene tres oportunidades de ganar, punto).
Kyle Clegg
2
La presentación de Meier se basa en el uso de Android Backup Manager, que a su vez depende de que el usuario elija activar esa función. Eso está bien para las preferencias de usuario de la aplicación (uso de Meier), porque si el usuario no ha seleccionado esa opción, simplemente no obtendrá una copia de seguridad de las mismas. Sin embargo, la pregunta original es sobre la generación de una identificación única para el dispositivo , y esta identificación se genera por aplicación, y ni siquiera por instalación, y mucho menos por dispositivo, y dado que depende de que el usuario seleccione la opción de copia de seguridad, su uso va más allá del usuario Las preferencias (p. ej., para una prueba de tiempo limitado) son limitadas.
Carl
12
Esto no funcionará en una desinstalación o borrado de datos.
John Shelley
106

También puede considerar la dirección MAC del adaptador Wi-Fi. Recuperado así:

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

Requiere permiso android.permission.ACCESS_WIFI_STATEen el manifiesto.

Se informó que está disponible incluso cuando el Wi-Fi no está conectado. Si Joe de la respuesta anterior prueba este en sus muchos dispositivos, sería bueno.

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

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

Seva Alekseyev
fuente
8
Esto se requiereandroid.permission.ACCESS_WIFI_STATE
ohhorob
55
Creo que descubrirá que no está disponible cuando WiFi está apagado, en casi todos los dispositivos Android. Desactivar WiFi elimina el dispositivo a nivel del núcleo.
chrisdowney
12
@Sanandrea: seamos sinceros, en un dispositivo rooteado TODO puede ser falsificado.
ocodo
55
El acceso a la dirección MAC de WiFi ha sido bloqueado en Android M: stackoverflow.com/questions/31329733/…
breez
66
Desde Android 6.x, devuelve una dirección mac falsa constante:02:00:00:00:00:00
Behrouz.M
87

Hay información bastante útil aquí .

Cubre cinco tipos de ID diferentes:

  1. IMEI (solo para dispositivos Android con uso del teléfono; necesidades android.permission.READ_PHONE_STATE)
  2. ID pseudounica (para todos los dispositivos Android)
  3. ID de Android (puede ser nulo, puede cambiar al restablecer los valores de fábrica, puede modificarse en el teléfono rooteado)
  4. Dirección MAC de WLANCadena de (necesita android.permission.ACCESS_WIFI_STATE)
  5. Cadena de dirección MAC BT (dispositivos con Bluetooth, necesidades android.permission.BLUETOOTH)
stansult
fuente
2
Punto importante omitido (aquí y en el artículo): ¡no puede obtener WLAN o BT MAC a menos que estén activados! De lo contrario, creo que el WLAN MAC sería el identificador perfecto. No tiene ninguna garantía de que el usuario pueda encender su Wi-Fi, y realmente no creo que sea 'apropiado' encenderlo usted mismo.
Tom
1
@ Tom, te equivocas. Todavía puede leer WLAN o BT MAC incluso cuando están apagados. Sin embargo, no hay garantía de que el dispositivo tenga módulos WLAN o BT disponibles.
Marqs
2
En particular, las direcciones locales de WiFi y Bluetooth MAC ya no están disponibles. El método getMacAddress () de un objeto aWifiInfo y el método BluetoothAdapter.getDefaultAdapter (). GetAddress () devolverán02: 00: 00: 00: 00: 00 de ahora en adelante
sarika kate
44
@sarikakate Es cierto solo en 6.0 Marshmallow y superior ... Todavía funciona como se esperaba en debajo de 6.0 Marshmallow.
Smeet
@Smeet Sí, tienes razón. Olvidé mencionar que funciona por debajo de 6.0
sarika kate
51

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

BoD
fuente
44
Y el punto clave de ese argumento es que si está tratando de obtener una identificación única del hardware, probablemente esté cometiendo un error.
Tim Bray
3
Y si permite que el bloqueo de su dispositivo se restablezca mediante un restablecimiento de fábrica, su modelo de prueba es tan bueno como muerto.
Seva Alekseyev
43

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

Este enfoque le proporcionará una identificación de usuario anónima y segura que será persistente para el usuario en diferentes dispositivos (según la cuenta principal de Google) y en todas las instalaciones. El enfoque básico es generar una identificación de usuario aleatoria y almacenarla en las preferencias compartidas de las aplicaciones. Luego, utiliza el agente de respaldo 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 deberá agregar al manifiesto. También debe indicarle a la aplicación que use el Agente de respaldo de la siguiente manera:

<application android:label="MyApplication"
         android:backupAgent="MyBackupAgent">
    ...
    <meta-data android:name="com.google.android.backup.api_key"
        android:value="your_backup_service_key" />
</application>

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;
}

Este User_ID ahora será persistente en todas las instalaciones, incluso si el usuario mueve el dispositivo.

Para obtener más información sobre este enfoque, consulte la charla de Reto .

Y para obtener detalles completos sobre cómo implementar el agente de copia de seguridad, consulte Copia de seguridad de datos . Recomiendo especialmente la sección en la parte inferior de las pruebas, ya que la copia de seguridad no se realiza instantáneamente, por lo que para realizar la prueba debe forzar la copia de seguridad.

TechnoTony
fuente
55
¿No conduce esto a múltiples dispositivos con la misma identificación cuando un usuario tiene múltiples dispositivos? Una tableta y un teléfono, por ejemplo.
Tosa
Se requiere un objetivo mínimo 8 para esto.
Halxinate el
¿Sería esta la forma preferida de crear una carga útil de verificación al realizar compras en la aplicación? Del comentario de código de ejemplo de facturación en la aplicación: "Entonces, una buena carga útil del desarrollador tiene estas características: 1. Si dos usuarios diferentes compran un artículo, la carga útil es diferente entre ellos, de modo que la compra de un usuario no se puede reproducir a otro usuario. 2. La carga útil debe ser tal que pueda verificarla incluso cuando la aplicación no fue la que inició el flujo de compra (de modo que los artículos comprados por el usuario en un dispositivo funcionen en otros dispositivos propiedad del usuario) ".
TouchBoarder
@Tosa Tenía la misma pregunta. ¿Pero no podríamos usar esta misma técnica nuevamente para crear identificadores de dispositivos virtuales y no respaldar eso de la misma manera? La identificación del dispositivo no persistiría después de un borrado o reinstalación, pero si tenemos una identificación de usuario persistente, es posible que no necesitemos tanto de una identificación del dispositivo.
Jwehrle
39

Creo que esta es una forma segura de construir un esqueleto para una identificación única ... échale un vistazo.

ID pseudo-único, que funciona en todos los dispositivos Android Algunos dispositivos no tienen un teléfono (por ejemplo, tabletas) o, por alguna razón, no desea incluir el permiso READ_PHONE_STATE. Todavía puede leer detalles como la versión de ROM, el nombre del fabricante, el tipo de CPU y otros detalles de hardware, que serán adecuados si desea utilizar la ID para una verificación de clave de serie u otros fines generales. La ID calculada de esta manera no será única: es posible encontrar dos dispositivos con la misma ID (basada en el mismo hardware e imagen de ROM), pero los cambios en las aplicaciones del mundo real son insignificantes. Para este propósito, puede usar la clase Build:

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

La mayoría de los miembros de Build son cadenas, lo que estamos haciendo aquí es tomar su longitud y transformarla a través de un módulo en un dígito. Tenemos 13 de estos dígitos y estamos agregando dos más al frente (35) para tener la misma ID de tamaño que el IMEI (15 dígitos). Hay otras posibilidades aquí están bien, solo eche un vistazo a estas cadenas. Devuelve algo como 355715565309247. No se requiere un permiso especial, lo que hace que este enfoque sea muy conveniente.


(Información adicional: la técnica proporcionada anteriormente se copió de un artículo sobre Pocket Magic ).

Lenn Dolling
fuente
77
Solución interesante Parece que esta es una situación en la que realmente deberías estar procesando todos esos datos concatenados en lugar de tratar de crear tu propia función "hash". Hay muchos casos en los que obtendría colisiones incluso si hay datos sustanciales que son diferentes para cada valor. Mi recomendación: usar una función hash y luego transformar los resultados binarios en decimal y truncarlo según sea necesario. Para hacerlo bien, aunque realmente debería usar un UUID o una cadena hash completa.
Steve Pomeroy
21
Debería dar crédito a sus fuentes ... Esto se ha sacado directamente del siguiente artículo: pocketmagic.net/?p=1662
Steve Haley
8
Esta identificación está abierta a colisiones como si no supiera qué. Prácticamente se garantiza que sea igual en dispositivos idénticos del mismo proveedor.
Seva Alekseyev
77
Esto también puede cambiar si el dispositivo se actualiza.
David dado el
8
Muy, muy mala solución. Probado en dos Nexus 5 ... Devuelve los mismos números.
Sinan Dizdarević
38

El siguiente código devuelve el número de serie del dispositivo utilizando una API de Android oculta. Pero este código no funciona en Samsung Galaxy Tab porque "ro.serialno" no está configurado en este dispositivo.

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) {

}
Roman SL
fuente
Acabo de leer en xda developer que ro.serialnose usa para generar el Settings.Secure.ANDROID_ID. Entonces son básicamente representaciones diferentes del mismo valor.
Martin
@ Martin: pero probablemente el número de serie no cambia al reiniciar el dispositivo. ¿No es así? Solo ANDROID_IDse deriva un nuevo valor para .
Ronnie
En realidad, en todos los dispositivos que he probado, eran idénticos. O al menos los valores hash donde son los mismos (por razones de privacidad no escribo los valores verdaderos en los archivos de registro).
Martin
Este valor es el mismo queandroid.os.Build.SERIAL
eugeneek
android.os.Build.SERIALquedará en desuso en Android O, consulte android-developers.googleblog.com/2017/04/…
EpicPandaForce
32

Es una pregunta simple, sin respuesta simple.

Además, todas las respuestas existentes aquí son obsoletas o poco confiables.

Entonces, si estás buscando una solución en 2020 .

Aquí hay algunas cosas a tener en cuenta:

Todos los identificadores basados ​​en hardware (SSAID, IMEI, MAC, etc.) no son confiables para dispositivos que no son de Google (todo excepto píxeles y nexos), que son más del 50% de los dispositivos activos en todo el mundo. Por lo tanto, las mejores prácticas de los identificadores oficiales de Android establecen claramente:

Evite usar identificadores de hardware , como SSAID (ID de Android), IMEI, dirección MAC, etc.

Eso hace que la mayoría de las respuestas anteriores no sean válidas. También debido a las diferentes actualizaciones de seguridad de Android, algunas de ellas requieren permisos de ejecución más nuevos y más estrictos, que el usuario puede simplemente negar.

Como ejemplo CVE-2018-9489 que afecta a todas las técnicas basadas en WIFI mencionadas anteriormente.

Eso hace que esos identificadores no solo sean poco confiables, sino también inaccesibles en muchos casos.

En palabras más simples: no uses esas técnicas .

Muchas otras respuestas aquí sugieren usar el AdvertisingIdClient, que también es incompatible, ya que por diseño solo debe usarse para la creación de perfiles publicitarios. También se indica en la referencia oficial.

Solo use una ID de publicidad para la creación de perfiles de usuario o casos de uso de anuncios

No solo no es confiable para la identificación del dispositivo, sino que también debe respetar la privacidad del usuario con respecto al seguimiento de anuncios política de , que establece claramente que el usuario puede restablecerla o bloquearla en cualquier momento.

Así que tampoco lo uses .

Dado que no puede tener el identificador de dispositivo estático globalmente único y confiable deseado. La referencia oficial de Android sugiere:

Utilice un FirebaseInstanceId o un GUID almacenado de forma privada siempre que sea posible para todos los demás casos de uso, excepto para la prevención del fraude de pagos y la telefonía.

Es único para la instalación de la aplicación en el dispositivo, por lo que cuando el usuario desinstala la aplicación, se borra, por lo que no es 100% confiable, pero es la mejor opción.

Para usar, FirebaseInstanceIdagregue la última dependencia de mensajería firebase en su gradle

implementation 'com.google.firebase:firebase-messaging:20.2.0'

Y use el siguiente código en un hilo de fondo:

String reliableIdentifier = FirebaseInstanceId.getInstance().getId();

Si necesita almacenar la identificación del dispositivo en su servidor remoto, no la guarde tal cual (texto sin formato), sino un hash con sal .

Hoy no es solo una mejor práctica, sino que debe hacerlo por ley de acuerdo con GDPR: identificadores y regulaciones similares.

Nikita Kurtin
fuente
3
Por ahora, esta es la mejor respuesta, y la primera frase es el mejor resumen: "Es una pregunta simple, sin una respuesta simple - me encanta.
b2mob
Debe apreciar el comentario "a excepción de la prevención del fraude de pagos y la telefonía" sin que se proporcione una respuesta sobre cómo abordar ese caso de uso.
Eran Boudjnah
@EranBoudjnah Esa cita de la referencia oficial, que está vinculada en la respuesta. Puedo intentar abordar ese caso de uso, pero como no es específico de la pregunta de OP, de acuerdo con la política de stackoverflow, debe hacerse en una pregunta específica separada.
Nikita Kurtin
Solo digo que la respuesta está incompleta. Pero sé que no es tu culpa, ya que es una cita.
Eran Boudjnah
1
@ M.UsmanKhan, la respuesta está escrita justo después de eso: " Hoy no es solo una mejor práctica, en realidad debe hacerlo por ley de acuerdo con GDPR - identificadores y regulaciones similares " .
Nikita Kurtin
27

Usando el código a continuación, puede obtener la ID única del dispositivo de un dispositivo con sistema operativo Android como una cadena.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
Mohit Kanada
fuente
21

Se agregó un campo Serie a la Buildclase en el nivel API 9 (Android 2.3 - Gingerbread) La documentación dice que representa el número de serie del hardware. Por lo tanto, debe ser único, si existe en el dispositivo.

Sin embargo, no sé si realmente es compatible (= no nulo) con todos los dispositivos con nivel de API> = 9.

rony l
fuente
2
Desafortunadamente, es "desconocido".
m0skit0
18

Añadiré una cosa: tengo una de esas situaciones únicas.

Utilizando:

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

Resulta que a pesar de que mi tableta Viewsonic G informa un DeviceID que no es nulo, cada tableta G informa el mismo número.

Lo hace interesante jugar "Pocket Empires", que le brinda acceso instantáneo a la cuenta de alguien en función del DeviceID "único".

Mi dispositivo no tiene una radio celular.

Tony Maro
fuente
¿Cuál es la identificación? ¿es acaso 9774d56d682e549c?
Mr_and_Mrs_D
Wow, eso fue hace tanto tiempo que desde hace mucho tiempo arrojé esa tableta. No se pudo decir.
Tony Maro
Trabajos. Además, es mucho más compacto que el ID que obtengo del UUID aleatorio.
Treewallie
1
@Treewallie ¿funciona? ¿Puedes obtener la misma ID de dispositivo de diferentes aplicaciones?
Arnold Brown
@ArnoldBrown Sí. Asegúrese de probarlo a fondo. Que tenga un buen día: D
Treewallie
16

Para obtener instrucciones detalladas sobre cómo obtener un identificador único para cada dispositivo Android desde el que se instala su aplicación, consulte el blog oficial de desarrolladores de Android que publica las instalaciones de aplicaciones de identificación .

Parece que la mejor manera es generar uno usted mismo después de la instalación y luego leerlo cuando se reinicia la aplicación.

Personalmente encuentro esto aceptable pero no ideal. Ningún identificador proporcionado por Android funciona en todos los casos, ya que la mayoría depende de los estados de radio del teléfono (activación / desactivación de Wi-Fi, activación / desactivación de celular, activación / desactivación de Bluetooth). Los demás, como Settings.Secure.ANDROID_IDdeben ser implementados por el fabricante y no se garantiza que sean únicos.

El siguiente es un ejemplo de escritura de datos en un archivo de instalación que se almacenaría junto con cualquier otro dato que la aplicación guarde localmente.

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();
    }
}
Kevin Parker
fuente
Si desea realizar un seguimiento de las instalaciones de la aplicación, esto es perfecto. Sin embargo, rastrear dispositivos es mucho más complicado, y no parece haber una solución completamente hermética.
Luca Spiller
¿Qué pasa con los dispositivos rooteados? Pueden cambiar esta identificación de instalación fácilmente, ¿verdad?
tasomaniac
Absolutamente. Root puede cambiar la ID de instalación. Puede verificar la raíz utilizando este bloque de código: stackoverflow.com/questions/1101380/…
Kevin Parker
Si restablecemos la configuración de fábrica, ¿se eliminará el archivo?
Jamshid
Si restablece los valores de fábrica y elimina o formatea la partición / data, el UUID es diferente.
Kevin Parker
12

Agregue el siguiente código en el archivo de clase:

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);

Agregar en AndroidManifest.xml:

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

El ID de dispositivo único de un dispositivo con sistema operativo Android como String, usando TelephonyManagery ANDROID_ID, se obtiene mediante:

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);
}

Pero recomiendo encarecidamente un método sugerido por Google, consulte Identificación de instalaciones de aplicaciones .

Jorgesys
fuente
9

Hay muchos enfoques diferentes para ANDROID_IDsolucionar esos problemas (a nullveces, los dispositivos de un modelo específico siempre devuelven la misma ID) con pros y contras:

  • Implementación de un algoritmo de generación de ID personalizado (basado en las propiedades del dispositivo que se supone que son estáticas y no cambiarán -> quién sabe)
  • Abusar de otras identificaciones como IMEI , número de serie, dirección Wi-Fi / Bluetooth-MAC (no existirán en todos los dispositivos o serán necesarios permisos adicionales)

Yo mismo prefiero usar una implementación de OpenUDID existente (consulte https://github.com/ylechelle/OpenUDID ) para Android (consulte https://github.com/vieux/OpenUDID ). Es fácil de integrar y hace uso de los ANDROID_IDretrocesos para los problemas mencionados anteriormente.

Andreas Klöber
fuente
8

¿Qué tal el IMEI ? Eso es único para Android u otros dispositivos móviles.

Elzo Valugi
fuente
99
No para mis tabletas, que no tienen un IMEI ya que no se conectan a mi operador de telefonía móvil.
Brill Pappin
2
Sin mencionar los dispositivos CDMA que tienen un ESN en lugar de un IMEI.
David dado el
@David Given ¿hay algún CDMA con Android?
Elzo Valugi
1
Solo lo hará si es un teléfono :) Es posible que una tableta no lo haga .
Brill Pappin
3
@ElzoValugi Ya es "estos días" y todavía no todas las tabletas tienen tarjetas SIM.
Matthew Quiros
8

Así es como estoy generando la identificación única:

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 (i.e. Wi-Fi MAC, Bluetooth MAC, etc.)

    return null;
}
Eng.Fouad
fuente
si usamos ReadPhoneState en la versión 6.0 pidiendo permiso de tiempo de ejecución
Harsha
8

Mis dos centavos, NB, esto es para una identificación única del dispositivo (err) , no para la instalación, como se discutió en el blog de desarrolladores de Android .

Tenga en cuenta que la solución proporcionada por @emmby recae en un ID por aplicación, ya que SharedPreferences no se sincronizan en todos los procesos (consulte aquí y aquí ). Así que evité esto por completo.

En cambio, encapsulé las diversas estrategias para obtener una ID de (dispositivo) en una enumeración: cambiar el orden de las constantes de enumeración afecta la prioridad de las diversas formas de obtener la ID. Se devuelve el primer ID no nulo o se lanza una excepción (según las buenas prácticas de Java de no dar un significado nulo). Entonces, por ejemplo, primero tengo el TELEPHONY, pero una buena opción predeterminada sería la beta ANDROID_ID :

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);
        }
    }
}
Mr_and_Mrs_D
fuente
8

Aquí hay más de 30 respuestas y algunas son iguales y otras son únicas. Esta respuesta se basa en pocas de esas respuestas. Uno de ellos es la respuesta de @Lenn Dolling.

Combina 3 ID y crea una cadena hexadecimal de 32 dígitos. Me ha funcionado muy bien.

3 ID son:
Pseudo-ID : se genera en función de las especificaciones del dispositivo físico
ANDROID_ID - Settings.Secure.ANDROID_ID
Dirección de Bluetooth - Dirección del adaptador de Bluetooth

Devolverá algo como esto: 551F27C060712A72730B0A0F734064B1

Nota: Siempre puede agregar más ID a la longIdcadena. Por ejemplo, número de serie. Dirección del adaptador wifi. IMEI De esta manera, lo está haciendo más único por dispositivo.

@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 "";
}
ᴛʜᴇᴘᴀᴛᴇʟ
fuente
1
Añadiendo el UUID a la longIdy almacenarlo en un archivo, lo hará el identificador más exclusivo:String uuid = UUID.randomUUID().toString();
Mousa Alfhaily
1
Si todo lo demás falla, si el usuario tiene una API inferior a 9 (inferior a Gingerbread), ha restablecido su teléfono o 'Secure.ANDROID_ID'. si devuelve 'nulo', simplemente la ID devuelta se basará únicamente en la información de su dispositivo Android. Aquí es donde pueden ocurrir las colisiones. Intente no usar DISPLAY, HOST o ID: estos elementos podrían cambiar. Si hay colisiones, habrá datos superpuestos. La fuente: gist.github.com/pedja1/fe69e8a80ed505500caa
Mousa Alfhaily
Si intentamos obtener un número único por esta línea de código, ¿podemos decir que es Id único y nunca entrará en conflicto con ningún otro dispositivo?
Ninja
1
@Ninja Dado que la dirección mac BLE es única, sí, la ID generada siempre será única. Sin embargo, si realmente quiere estar seguro, sugeriría agregar un UUID al longId. Cambie esa línea de esta manera: String longId = pseudoId + androidId + btId + UUID.randomUUID().toString();esto garantiza que la ID generada será única.
ᴛʜᴇᴘᴀᴛᴇʟ
@ ᴛʜᴇᴘᴀᴛᴇʟ Muchas gracias por esta gran ayuda. En realidad, mi aplicación tiene datos muy confidenciales, así que necesito asegurarme de eso, por eso solo estoy confirmando estas cosas.
Ninja el
7

Otra forma es usar /sys/class/android_usb/android0/iSerialen una aplicación sin ningún tipo de permiso.

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

Para hacer esto en Java, uno simplemente usaría FileInputStream para abrir el archivo iSerial y leer los caracteres. Solo asegúrese de incluirlo en un controlador de excepciones, porque no todos los dispositivos tienen este archivo.

Se sabe que al menos los siguientes dispositivos tienen este archivo legible en todo el mundo:

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

También puede ver la publicación de mi blog Filtrando el número de serie del hardware de Android en aplicaciones no privilegiadas donde analizo qué otros archivos están disponibles para obtener información.

insitusec
fuente
Acabo de leer tu publicación de blog. Creo que esto no es único: Build.SERIAL también está disponible sin ningún permiso, y es (en teoría) un número de serie de hardware único.
Tom
1
Tienes razón. Es solo una forma más de que se pueda rastrear su dispositivo, y como usted dijo, ambas formas no requieren permisos de aplicación.
insitusec
7

TelephonyManger.getDeviceId () Devuelve la ID única del dispositivo, por ejemplo, el IMEI para GSM y el MEID o ESN para teléfonos CDMA.

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

Pero recomiendo usar:

Settings.Secure.ANDROID_ID que devuelve la ID de Android como una cadena hexadecimal única de 64 bits.

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

A veces, TelephonyManger.getDeviceId () devolverá un valor nulo, por lo que para garantizar una identificación única, utilizará este método:

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;
}
Jorgesys
fuente
Recientemente descubrí que el dispositivo de un cliente del tipo SM-G928F / Galaxy S6 edge + ofrece solo 15 en lugar de 16 dígitos hexadecimales para la ID de Android.
Holger Jakobs
7

Para el reconocimiento de hardware de un dispositivo Android específico, puede verificar las direcciones MAC.

puedes hacerlo de esa manera:

en AndroidManifest.xml

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

ahora en tu código:

List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());

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

En cada dispositivo Android, existe al menos una interfaz "wlan0", que es el chip WI-FI. Este código funciona incluso cuando WI-FI no está encendido.

PD: Hay muchas otras interfaces que obtendrá de la lista que contiene MACS. Pero esto puede cambiar entre teléfonos.

Ilan.b
fuente
7

Utilizo el siguiente código para obtener IMEIo usar Secure. ANDROID_IDcomo alternativa, cuando el dispositivo no tiene capacidades telefónicas:

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);
Asaf Pinhassi
fuente
7

Más específicamente Settings.Secure.ANDROID_ID,. Esta es una cantidad de 64 bits que se genera y almacena cuando el dispositivo se inicia por primera vez. Se restablece cuando se limpia el dispositivo.

ANDROID_IDParece una buena opción para un identificador de dispositivo único. Hay inconvenientes: en primer lugar, no es 100% confiable en las versiones de Android anteriores a 2.2 (“Froyo”).Además, ha habido al menos un error ampliamente observado en un teléfono popular de un fabricante importante, donde cada instancia tiene el mismo ANDROID_ID.

mumu123
fuente
1
esta respuesta es una copia del antiguo blog de google android-developers.googleblog.com/2011/03/… . ¿Entonces el error ya está resuelto?
Sergii
7

Para comprender los ID únicos disponibles en dispositivos Android. Utiliza esta guía oficial.

Mejores prácticas para identificadores únicos:

IMEI, direcciones Mac, ID de instancia, GUID, SSAID, ID de publicidad, API de Safety Net para verificar dispositivos.

https://developer.android.com/training/articles/user-data-ids

Waheed Nazir
fuente
6

ID de instancia de Google

Lanzado en I / O 2015; en Android requiere servicios de reproducción 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

Parece que Google tiene la intención de que esta ID se use para identificar instalaciones en Android, Chrome e iOS.

Identifica una instalación en lugar de un dispositivo, pero nuevamente, ANDROID_ID (que es la respuesta aceptada) ahora ya no identifica dispositivos. Con el tiempo de ejecución ARC, se genera un nuevo ANDROID_ID para cada instalación ( detalles aquí ), al igual que este nuevo ID de instancia. Además, creo que identificar instalaciones (no dispositivos) es lo que la mayoría de nosotros estamos buscando.

Las ventajas de la identificación de instancia

Me parece que Google tiene la intención de que se use para este propósito (identificación de sus instalaciones), es multiplataforma y se puede usar para una serie de otros fines (consulte los enlaces anteriores).

Si usa GCM, eventualmente necesitará usar esta ID de instancia porque la necesita para obtener el token GCM (que reemplaza la ID de registro de GCM anterior).

Las desventajas / problemas

En la implementación actual (GPS 7.5), el ID de la instancia se recupera de un servidor cuando su aplicación lo solicita. Esto significa que la llamada anterior es una llamada de bloqueo: en mis pruebas no científicas, toma 1-3 segundos si el dispositivo está en línea, y 0.5 - 1.0 segundos si está fuera de línea (presumiblemente, este es el tiempo que espera antes de darse por vencido y generar un ID al azar). Esto se probó en América del Norte en Nexus 5 con Android 5.1.1 y GPS 7.5.

Si utiliza la identificación para los fines que pretenden, por ejemplo. autenticación de la aplicación, identificación de la aplicación, GCM: creo que estos 1-3 segundos pueden ser una molestia (dependiendo de su aplicación, por supuesto).

Tom
fuente
1
Otro inconveniente significativo de la instancia de ID es que se generará una nueva ID de instancia para usted si el usuario borra los datos de la aplicación.
idanakav
Interesante, pero no creo que realmente cambie los casos de uso potenciales: la ID de instancia, como android_id, no es adecuada para identificar un dispositivo. Por lo tanto, su servidor verá los datos de eliminación de usuarios como desinstalar y volver a instalar su aplicación, lo que no es irrazonable.
Tom