¿Cómo encontrar el número de serie del dispositivo Android?


115

Necesito usar una identificación única para una aplicación de Android y pensé que el número de serie del dispositivo sería un buen candidato. ¿Cómo recupero el número de serie de un dispositivo Android en mi aplicación?


2
No olvide agregar android: name = "android.permission.READ_PHONE_STATE" a su manifiesto
Michael SIlveus


Si desea obtener una identificación única sin ningún permiso, puede usar esta biblioteca para generar una identificación única por dispositivo con Identity.getDeviceId (contexto) o un identificador para la instalación de su aplicación a través de Identity.getInstallationId (contexto) .
caw

Respuestas:


105
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();

getSystemService es un método de la clase Activity. getDeviceID () devolverá el MDN o MEID del dispositivo según la radio que utilice el teléfono (GSM o CDMA).

Cada dispositivo DEBE devolver un valor único aquí (suponiendo que sea un teléfono). Esto debería funcionar para cualquier dispositivo Android con una ranura SIM o radio CDMA. Estás solo con ese microondas con Android ;-)


@Hasemam Esto no funciona para mí, dando el error "Forzar cierre"
Paresh Mayani

23
@Hasemam está funcionando bien ahora después de agregar el permiso <uses-allow android: name = "android.permission.READ_PHONE_STATE"> </uses-permission> en el archivo androidManifest.xml.
Paresh Mayani

23
Hay algunos consejos en el blog oficial del desarrollador de Android sobre el uso de este identificador: android-developers.blogspot.com/2011/03/…
David Snabel-Caunt

8
Aparte del microondas con Android, ¿qué pasa con una tableta con Android? :)
ajacian81

21
Se debe evitar este método, esto funcionará en teléfonos pero no funcionará en dispositivos sin un chip de teléfono (las tabletas son un ejemplo). Desde 2.3, puede usar android.os.Build.SERIAL, pero consulte el blog para desarrolladores que sugirió @DavidCaunt.
John Mitchell

71

Como menciona Dave Webb, el Blog para desarrolladores de Android tiene un artículo que cubre esto.

Hablé con alguien de Google para obtener aclaraciones adicionales sobre algunos elementos. Esto es lo que descubrí que NO se menciona en la publicación del blog antes mencionada:

  • ANDROID_ID es la solución preferida. 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.
  • Por lo que 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 fabricantes de equipos originales 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 tienen el ANDROID_ID roto.

De acuerdo con las recomendaciones de Google, implementé una clase que generará un UUID único para cada dispositivo, usando ANDROID_ID como semilla cuando 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).

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

1
¿Qué permisos se requieren para que una aplicación use esto?
Dave L.

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

1
@ ef2011 es el patrón de bloqueo verificado dos
veces

3
Gracias por publicar. Pero, ¿qué puede evitar que alguien con un teléfono rooteado simplemente edite device_id.xml para ingresar un nuevo UUID de su elección? (es decir, para eludir una verificación de 'prueba gratuita') ¿No sería mejor si la clase solo almacenara el valor en un archivo de preferencias si tuviera que recurrir al método de ID aleatorio? De lo contrario, no es necesario conservarlo entre ejecuciones de aplicaciones; es más seguro volver a generar.
Carlos P

1
"ANDROID_ID" es la solución preferida ". Tenga en cuenta que ANDROID_ID ya no identifica de forma exclusiva un dispositivo: stackoverflow.com/a/13465373/150016
Tom

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

Este código devuelve el número de serie del dispositivo mediante una API de Android oculta.


7
esto solo me da el mismo valor que el que obtengo con android.os.Build.SERIAL
josephus

¿Estoy equivocado o este número de serie es el mismo en todos los dispositivos con una rom personalizada específica? El número de serie de mi dispositivo (en el lanzador de dispositivos eclipse) muestra 01234567890ABC para un teléfono con una rom personalizada.
Peterdk

@Peterdk en mi dispositivo con cyanogen-9 ambos métodos (anterior a andy-9 como en la respuesta y el más fácil disponible de andy-9 en adelante) informan el s / n correcto (el mismo que en la etiqueta del fabricante). Sin embargo, puede depender de la versión de rom personalizada específica. ¿Qué rom / versión estás usando?
morgwai

16
String deviceId = Settings.System.getString(getContentResolver(),
                                Settings.System.ANDROID_ID);

Sin embargo, no se garantiza que la ID de Android sea un identificador único.


@Paresh Mayani, es difícil saber cuál puede ser el problema sin mirar el código. Mi única suposición es que getContentResolverestá regresando null. Sin embargo, puede valer la pena abrir una pregunta y publicar su código.
Anthony Forloney

4
Esta identificación proviene de la cuenta de Google asociada con el teléfono. El simulador normalmente no tiene uno. Un teléfono real puede que tampoco lo tenga. Además, está documentado como "puede cambiar con el restablecimiento de fábrica" ​​y se puede cambiar arbitrariamente en cualquier momento en un teléfono rooteado. Úselo bajo su propio riesgo. No hay una buena alternativa: otras ID de dispositivo provisionales no están disponibles universalmente, o no son únicas, o ambas cosas. Vea otras respuestas para el resto de esta triste historia.
Seva Alekseyev

14

Hay una publicación excelente en el Blog de desarrolladores de Android que habla de esto .

Se recomienda no usarlo TelephonyManager.getDeviceId()ya que no funciona en dispositivos Android que no son teléfonos como tabletas, requiere elREAD_PHONE_STATE permiso y no funciona de manera confiable en todos los teléfonos.

En su lugar, puede utilizar uno de los siguientes:

  • Dirección MAC
  • Número de serie
  • ANDROID_ID

La publicación analiza los pros y los contras de cada uno y vale la pena leerlo para que pueda determinar cuál sería el mejor para su uso.


+1, hola dave, gracias por la aclaración porque en este momento estoy desarrollando una aplicación para la tableta, donde necesito tener una identificación única del dispositivo Android, entonces, ¿qué debo usar para obtener un dispositivo de tableta Android único?
Paresh Mayani

12

Para obtener un número simple que sea exclusivo del dispositivo y constante durante toda su vida (salvo que se realice un restablecimiento de fábrica o piratería), use Settings.Secure.ANDROID_ID .

String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);

Para usar el número de serie del dispositivo (el que se muestra en "Configuración del sistema / Acerca de / Estado") si está disponible y recurrir al ID de Android:

String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);

respuesta sencilla !!
faris faris

Build.SERİAL obsoleto en java
Eyyüp Alkış

7

El IMEI es bueno pero solo funciona en dispositivos Android con teléfono. También debe considerar la compatibilidad con tabletas u otros dispositivos Android que no tengan teléfono.

Tiene algunas alternativas como: miembros de la clase de compilación, BT MAC, WLAN MAC o incluso mejor, una combinación de todos estos.

He explicado estos detalles en un artículo de mi blog, consulte: http://www.pocketmagic.net/?p=1662


6

Dado que ninguna respuesta aquí menciona una identificación perfecta y a prueba de fallas que es PERSISTENTE a través de las actualizaciones del sistema y existe en TODOS los dispositivos (principalmente debido al hecho de que no hay una solución individual de Google), decidí publicar un método que es la siguiente mejor opción es combinar dos de los identificadores disponibles y una verificación para elegir entre ellos en tiempo de ejecución.

Antes del código, 3 hechos:

  1. TelephonyManager.getDeviceId()(akaIMEI) no funcionará bien o en absoluto para dispositivos que no sean GSM, 3G, LTE, etc., pero siempre devolverá una ID única cuando el hardware relacionado esté presente , incluso cuando no se inserte una SIM o incluso cuando no exista una ranura para SIM ( algunos OEM han hecho esto).

  2. Dado que Gingerbread (Android 2.3) android.os.Build.SERIAL debe existir en cualquier dispositivo que no proporcione IMEI , es decir, que no tenga presente el hardware mencionado anteriormente, según la política de Android.

  3. Debido al hecho (2.), al menos uno de estos dos identificadores únicos SIEMPRE estará presente , y SERIAL puede estar presente al mismo tiempo que el IMEI.

Nota: Los hechos (1.) y (2.) se basan en declaraciones de Google

SOLUCIÓN

Con los hechos anteriores, uno siempre puede tener un identificador único al verificar si hay hardware vinculado a IMEI, y recurrir a SERIAL cuando no lo es, ya que no se puede verificar si el SERIAL existente es válido. La siguiente clase estática presenta 2 métodos para verificar dicha presencia y usar IMEI o SERIAL:

import java.lang.reflect.Method;

import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;

public class IDManagement {

    public static String getCleartextID_SIMCHECK (Context mContext){
        String ret = "";

        TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

        if(isSIMAvailable(mContext,telMgr)){
            Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId());
            return telMgr.getDeviceId();

        }
        else{
            Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);

//          return Settings.Secure.ANDROID_ID;
            return android.os.Build.SERIAL;
        }
    }


    public static String getCleartextID_HARDCHECK (Context mContext){
        String ret = "";

        TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if(telMgr != null && hasTelephony(mContext)){           
            Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId() + "");

            return telMgr.getDeviceId();    
        }
        else{
            Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);

//          return Settings.Secure.ANDROID_ID;
            return android.os.Build.SERIAL;
        }
    }


    public static boolean isSIMAvailable(Context mContext, 
            TelephonyManager telMgr){

        int simState = telMgr.getSimState();

        switch (simState) {
        case TelephonyManager.SIM_STATE_ABSENT:
            return false;
        case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
            return false;
        case TelephonyManager.SIM_STATE_PIN_REQUIRED:
            return false;
        case TelephonyManager.SIM_STATE_PUK_REQUIRED:
            return false;
        case TelephonyManager.SIM_STATE_READY:
            return true;
        case TelephonyManager.SIM_STATE_UNKNOWN:
            return false;
        default:
            return false;
        }
    }

    static public boolean hasTelephony(Context mContext)
    {
        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if (tm == null)
            return false;

        //devices below are phones only
        if (Build.VERSION.SDK_INT < 5)
            return true;

        PackageManager pm = mContext.getPackageManager();

        if (pm == null)
            return false;

        boolean retval = false;
        try
        {
            Class<?> [] parameters = new Class[1];
            parameters[0] = String.class;
            Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
            Object [] parm = new Object[1];
            parm[0] = "android.hardware.telephony";
            Object retValue = method.invoke(pm, parm);
            if (retValue instanceof Boolean)
                retval = ((Boolean) retValue).booleanValue();
            else
                retval = false;
        }
        catch (Exception e)
        {
            retval = false;
        }

        return retval;
    }


}

Yo aconsejaría sobre el uso getCleartextID_HARDCHECK . Si el reflejo no se pega en su entorno, utilice el getCleartextID_SIMCHECKmétodo en su lugar, pero tenga en cuenta que debe adaptarse a sus necesidades específicas de presencia de SIM.

PD : tenga en cuenta que los OEM tienen logrado bloquear SERIAL contra la política de Google (varios dispositivos con la misma SERIAL), y Google, como se indicó, hay al menos un caso conocido en un gran OEM (no divulgado y no sé qué marca lo es, supongo que Samsung).

Descargo de responsabilidad : Esto responde a la pregunta original de obtener una ID de dispositivo única, pero el OP introdujo ambigüedad al afirmar que necesita una ID única para una APLICACIÓN. Incluso si para tales escenarios Android_ID sería mejor, NO FUNCIONARÁ después de, digamos, una copia de seguridad de titanio de una aplicación a través de 2 instalaciones de ROM diferentes (incluso puede ser la misma ROM). Mi solución mantiene una persistencia que es independiente de un flash o un restablecimiento de fábrica, y solo fallará cuando se produzca una manipulación de IMEI o SERIAL a través de hacks / modificaciones de hardware.


5

Hay problemas con todos los enfoques anteriores. En Google i / o, Reto Meier lanzó una respuesta sólida sobre cómo abordar esto, que debería satisfacer las necesidades de la mayoría de los desarrolladores de rastrear usuarios en todas las instalaciones.

Este enfoque le brindará una identificación de usuario segura y anónima que será persistente para el usuario en diferentes dispositivos (incluidas las tabletas, según la cuenta principal de Google) y en todas las instalaciones en el mismo dispositivo. El enfoque básico es generar una identificación de usuario aleatoria y almacenarla en las preferencias compartidas de las aplicaciones. Luego, usa el agente de respaldo de Google para almacenar las preferencias compartidas vinculadas a la cuenta de Google en la nube.

Repasemos el enfoque completo. Primero necesitamos crear una copia de seguridad para nuestras SharedPreferences usando el servicio de copia de seguridad de Android. Comience registrando su aplicación a través de este enlace: http://developer.android.com/google/backup/signup.html

Google le dará una clave de servicio de respaldo que debe agregar al manifiesto. También debe indicarle a la aplicación que use BackupAgent 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 guárdela 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 cambia de dispositivo.

Para obtener más información sobre este enfoque, consulte la charla de Reto aquí. http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html

Y para obtener detalles completos sobre cómo implementar el agente de respaldo, consulte el sitio para desarrolladores aquí: http://developer.android.com/guide/topics/data/backup.html Recomiendo particularmente la sección en la parte inferior sobre pruebas como lo hace el respaldo no suceda instantáneamente y, por lo tanto, para probar debe forzar la copia de seguridad.


2

Otra forma es usar / sys / class / android_usb / android0 / iSerial en una aplicación sin ningún 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 solo usaría un FileInputStream para abrir el archivo iSerial y leer los caracteres. Solo asegúrese de envolverlo 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 aquí: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html donde analizo qué otros archivos están disponibles para obtener información.


¡Gracias por publicar tu respuesta! Asegúrese de leer detenidamente las preguntas frecuentes sobre la autopromoción. También tenga en cuenta que es necesario que publique un descargo de responsabilidad cada vez que enlace a su propio sitio / producto.
Andrew Barber

1

Como dice @haserman:

TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();

Pero es necesario incluir el permiso en el archivo de manifiesto:

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

1

ID de dispositivo único del dispositivo con sistema operativo Android como cadena.

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 este método sugerido por Google:

Identificación de instalaciones de aplicaciones


1

Build.SERIALes la forma más sencilla de hacerlo, aunque no es del todo confiable, ya que puede estar vacío o, a veces, devolver un valor diferente ( prueba 1 , prueba 2 ) del que puede ver en la configuración de su dispositivo.

Hay varias formas de obtener ese número según el fabricante del dispositivo y la versión de Android, así que decidí compilar todas las soluciones posibles que pude encontrar en una sola esencia . Aquí hay una versión simplificada:

public static String getSerialNumber() {
    String serialNumber;

    try {
        Class<?> c = Class.forName("android.os.SystemProperties");
        Method get = c.getMethod("get", String.class);

        serialNumber = (String) get.invoke(c, "gsm.sn1");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ril.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ro.serialno");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "sys.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = Build.SERIAL;

        // If none of the methods above worked
        if (serialNumber.equals(""))
            serialNumber = null;
    } catch (Exception e) {
        e.printStackTrace();
        serialNumber = null;
    }

    return serialNumber;
}

0

Sé que esta pregunta es antigua, pero se puede hacer en una línea de código.

String deviceID = Build.SERIAL;


AFAIK, esto cambiará después de la actualización del sistema operativo del dispositivo, por ejemplo, de 4.4.2 a 4.4.4 o lo que sea.
Den Drobiazko

-1

Encontré que la clase de ejemplo publicada por @emmby arriba es un excelente punto de partida. Pero tiene un par de defectos, como lo mencionan otros carteles. El principal es que persiste el UUID en un archivo XML innecesariamente y, a partir de entonces, siempre lo recupera de este archivo. Esto abre la clase a un truco fácil: cualquier persona con un teléfono rooteado puede editar el archivo XML para obtener un nuevo UUID.

Actualicé el código para que solo persista en XML si es absolutamente necesario (es decir, cuando se usa un UUID generado aleatoriamente) y modifiqué la lógica según la respuesta de @Brill Pappin:

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 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) || (androidId == null) ) {
                                final String deviceId = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE )).getDeviceId();

                                if (deviceId != null)
                                {
                                    uuid = UUID.nameUUIDFromBytes(deviceId.getBytes("utf8"));
                                }
                                else
                                {
                                    uuid = UUID.randomUUID();

                                    // Write the value out to the prefs file so it persists
                                    prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString() ).commit();
                                }
                            }
                            else
                            {
                                uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
                            } 
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }



                    }

                }
            }
        }

    }


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

Poner la identificación en preferencias compartidas compromete el objetivo original de obtener una identificación realmente única. Por ejemplo, si desea utilizar esa identificación como clave para algunas restricciones, se arruinará cuando los usuarios expertos rooteen un dispositivo y obtengan acceso a su archivo de preferencias compartido. Su contenido se puede copiar, lo que significa ...
Eugene Wechsler

También hay otro error en la respuesta de MB y la tuya. Si usas randomUUID como deviceID y appID, funciona para todos los dispositivos en todo el territorio, sin importar si son teléfonos o no o si son dispositivos de Google exp o no.
Fred Grott

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.