uniqueidentifier identificador - ¿Hay un ID de dispositivo Android único?




obtener saber (25)

Una cosa que añadiré: 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 una de las tabletas G informa el mismo número.

Lo hace interesante al jugar "Pocket Empires", que le brinda acceso instantáneo a la cuenta de alguien basada en el "único" ID de dispositivo.

Mi dispositivo no tiene una radio celular.

¿Los dispositivos Android tienen una ID única y, en caso afirmativo, cuál es una forma sencilla de acceder a ella utilizando Java?


ID de instancia de Google

Lanzado en I / O 2015; en Android requiere servicios de juego 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 pretende que esta identificación 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 del ID de instancia

Me parece que Google pretende que se use para este propósito (identificando sus instalaciones), es multiplataforma y se puede usar para otros fines (consulte los enlaces anteriores).

Si usa GCM, finalmente necesitará usar este ID de instancia porque lo necesita para obtener el token de GCM (que reemplaza al antiguo ID de registro de GCM).

Las desventajas / problemas

En la implementación actual (GPS 7.5), la ID de instancia se recupera de un servidor cuando la aplicación lo solicita. Esto significa que la llamada de arriba es una llamada de bloqueo: en mi prueba no científica demora entre 1 y 3 segundos si el dispositivo está en línea, y entre 0,5 y 1,0 segundos si está desconectado (probablemente este es el tiempo que espera antes de darse por vencido y generar un mensaje). Identificación aleatoria). Esto fue probado 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 esto de 1 a 3 segundos podría ser una molestia (dependiendo de su aplicación, por supuesto)


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. Existen desventajas: primero, 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.


Para obtener instrucciones detalladas sobre cómo obtener un identificador único para cada dispositivo Android de su aplicación se instala desde, ver el oficial de Android Desarrolladores de Publicación android-developers.blogspot.com/2011/03/… .

Parece que la mejor manera es que usted mismo genere uno después de la instalación y luego lo lea cuando se reinicie la aplicación.

Personalmente me parece 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 (Wi-Fi activado / activado, activación / desactivación celular, Bluetooth activado / desactivado). Los otros, como Settings.Secure.ANDROID_IDdebe ser implementado 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();
    }
}


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

  • 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 cambian -> quién sabe)
  • Abusar de otras identificaciones como IMEI , número de serie, Wi-Fi / Bluetooth-MAC (no existirán en todos los dispositivos o se necesitarán permisos adicionales)

Yo mismo prefiero usar una implementación existente de OpenUDID (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_IDrecursos alternativos para los problemas mencionados anteriormente.


TelephonyManger.getDeviceId () Devuelve el ID de dispositivo único, 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 única cadena hex de 64 bits.

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

A veces, TelephonyManger.getDeviceId () devolverá un valor nulo, por lo que para asegurar una identificación única, usarás 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;
}

Hay más de 30 respuestas aquí y algunas son iguales y otras son únicas. Esta respuesta se basa en algunas de esas respuestas. Una de ellas es la respuesta de @Lenn Dolling.

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

Las 3 ID son:
Pseudo-ID : se genera según las especificaciones físicas del dispositivo
ANDROID_ID - Settings.Secure.ANDROID_ID
Dirección de Bluetooth - Dirección del adaptador de Bluetooth

Devolverá algo como esto: 551F27C060712A72730B0A0F734064B1

Nota: siempre puedes agregar más ID a la longIdcadena. Por ejemplo, número de serie. Dirección del adaptador wifi. IMEI. De esta manera lo estás 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 "";
}

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

Añadir en AndroidManifest.xml:

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

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

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

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

Si combina esto con una estrategia de copia de seguridad para enviar preferencias a la nube (también se describe en la talk de Reto, debe tener un ID que se vincule a un usuario y permanezca después de que el dispositivo haya sido borrado o incluso reemplazado. Planeo usar esto en analítica en adelante (en otras palabras, todavía no he hecho un poco).


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


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

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 .


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 hacer un seguimiento de los usuarios en 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 averiguar los detalles).

Este enfoque le dará una identificación de usuario segura y anónima que será persistente para el usuario en diferentes dispositivos (según la cuenta de Google principal) y en las instalaciones. El enfoque básico es generar un ID de usuario aleatorio y almacenar esto 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.

Vamos a pasar por el enfoque completo. Primero, debemos crear una copia de seguridad para nuestras SharedPreferences utilizando 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 proporcionará una clave de servicio de respaldo que debe agregar al manifiesto. También debe indicar 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 necesita crear el agente de respaldo y decirle que use el agente auxiliar para las referencias 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 un ID de usuario, si aún no existe, y almacénelo en las 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 ID de usuario ahora será persistente en todas las instalaciones, incluso si el usuario mueve el dispositivo.

Para más información sobre este enfoque, vea talk .

Y para obtener información detallada sobre cómo implementar el agente de respaldo, consulte Copia de seguridad de datos . En particular, recomiendo la sección en la parte inferior sobre las pruebas, ya que la copia de seguridad no se realiza de forma instantánea, por lo que para probarla debe forzar la copia de seguridad.


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

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

Requiere permiso android.permission.ACCESS_WIFI_STATE en el manifiesto.

Se informa que está disponible incluso cuando el Wi-Fi no está conectado. Si Joe de la respuesta anterior le da a éste un intento en sus muchos dispositivos, sería bueno.

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

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


Mis dos centavos: NB, esto es para una ID única de dispositivo (error) , no para la instalación como se explica en el blog de desarrolladores de Android .

Es de destacar que la solution provista por @emmby recae en un ID por aplicación ya que las SharedPreferences no se sincronizan entre los procesos (consulte here y here ). Así que evité esto por completo.

En su lugar, encapsulé las diversas estrategias para obtener un ID (dispositivo) en una enumeración: cambiar el orden de las constantes enumistas afecta la prioridad de las diversas formas de obtener el ID. Se devuelve la primera ID que no es nula o se lanza una excepción (según las buenas prácticas de Java de no dar un significado nulo). Así, por ejemplo, primero tengo la TELEFONÍA, 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);
        }
    }
}

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

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID); 

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

[email protected]:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
[email protected]:~$ adb shell cat /sys/class/android_usb/android0/iSerial
0A3CXXXXXXXXXX5

Para hacer esto en Java uno solo usaría FileInputStream para abrir el archivo iSerial y leer los caracteres. Solo asegúrese de envolverlo en un controlador de excepciones, ya que 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. Filtrar el número de serie del hardware de Android a aplicaciones sin privilegios donde discuto qué otros archivos están disponibles para obtener información.


Última actualización: 6/2/15

Después de leer cada publicación de sobre la creación de una ID única, el blog del desarrollador de Google y la documentación de Android, siento que la "Pseudo ID" es la mejor opción posible.

Tema principal: Hardware vs Software

Hardware

  • Los usuarios pueden cambiar su hardware, tableta o teléfono Android, por lo que las identificaciones únicas basadas en hardware no son buenas ideas para los usuarios de seguimiento
  • Para TRACKING HARDWARE , esta es una gran idea

Software

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

Desglose global con Android

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

- No hay 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 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 que / por qué no usarlas:

  • Correo electrónico del usuario - Software

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

    • Los usuarios podrían cambiar los números de teléfono - MUY improbable
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Hardware (solo teléfonos, necesita android.permission.READ_PHONE_STATE )

    • La mayoría de los usuarios odian el hecho de que dice "Llamadas telefónicas" en el permiso. Algunos usuarios dan malas calificaciones, porque creen que simplemente está robando su información personal, cuando todo lo que realmente quiere hacer es rastrear las instalaciones del dispositivo. Es obvio que estás recolectando datos.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • ID de Android: el hardware (puede ser nulo, puede cambiarse al restablecerse en la fábrica, se puede modificar en un dispositivo rooteado)

    • Ya que puede ser 'nulo', podemos verificar 'nulo' y cambiar su valor, pero esto significa que ya no será único.
    • Si tiene un usuario con un dispositivo de restablecimiento de fábrica, el valor puede haber cambiado o alterado en el dispositivo rooteado, por lo que puede haber entradas duplicadas si realiza el seguimiento de las instalaciones de los usuarios.
  • Dirección MAC de WLAN - Hardware (necesita 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ás recolectando datos.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Dirección MAC de Bluetooth - Hardware (dispositivos con Bluetooth, necesita android.permission.BLUETOOTH )

    • La mayoría de las aplicaciones en el mercado no usan Bluetooth, por lo tanto, si su aplicación no usa Bluetooth y usted lo incluye, el usuario podría sospechar.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-Unique ID - Software (para todos los dispositivos Android)

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

Sé que no hay ninguna forma 'perfecta' de obtener una ID única sin usar permisos; Sin embargo, a veces solo necesitamos realizar un seguimiento de 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 manera, podemos mostrar respeto al usuario y tratar de 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. Puedes modificar el método combinado para hacerlo más único; sin embargo, algunos desarrolladores necesitan hacer un seguimiento de las instalaciones de los dispositivos y esto hará el truco o el rendimiento en base a dispositivos similares.

API> = 9:

Si su dispositivo Android es API 9 o superior, se garantiza que es ú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 puedas concentrarte en el resto: ¡esto es el 99.5% de los usuarios!

API <9:

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

Si todo lo demás falla:

Si todo lo demás falla, si el usuario tiene menos de API 9 (más bajo que Gingerbread), ha restablecido su dispositivo o 'Secure.ANDROID_ID' devuelve 'null', simplemente la ID devuelta se basará exclusivamente en la información de su dispositivo Android. Aquí es donde pueden ocurrir las colisiones.

Cambios:

  • La eliminación de 'Android.SECURE_ID' debido a los restablecimientos de fábrica podría hacer que el valor cambie
  • Editado el código para cambiar en API
  • Cambiado el pseudo

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://.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://.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 aplicaciones nuevas se carguen y se actualicen para usar 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 / Docs:

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 la ID de publicidad reemplace completamente el uso existente de otros identificadores con fines publicitarios (como el uso de ANDROID_ID en Settings.Secure) cuando Google Play Services esté disponible. Los casos en los que Google Play Services no está disponible se indican mediante una excepción GooglePlayServicesNotAvailableException emitida por getAdvertisingIdInfo ().

Advertencia, los usuarios pueden restablecer:

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

He intentado hacer referencia a todos los enlaces de los que tomé información. Si falta y necesita ser incluido, por favor comente!

ID de instancia de servicios de Google Player

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


Google ahora tiene una identificación de publicidad .
Esto también se puede usar, pero tenga en cuenta que:

El ID de publicidad es un ID exclusivo de usuario, reiniciable

y

permite a los usuarios restablecer su identificador o rechazar anuncios basados ​​en intereses dentro de las aplicaciones de Google Play.

Entonces, aunque esta identificación puede cambiar, parece que pronto no tendremos una opción , depende del propósito de esta identificación.

http://developer.android.com/google/play-services/id.html

Copia y pega el código aquí

HTH


Utilizo el siguiente código para obtener IMEIo usar Secure. ANDROID_IDcomo alternativa, cuando el dispositivo no tiene capacidades de teléfono:

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

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

Revelación completa: mi aplicación usó el siguiente enfoque originalmente pero ya no lo utiliza, y ahora usamos el enfoque descrito en la entrada del android-developers.blogspot.com/2011/03/… que se vincula la respuesta de emmby (a saber, generar y guardar un UUID#randomUUID() ).

Hay muchas respuestas a esta pregunta, la mayoría de las cuales solo funcionarán "parte" del tiempo, y desafortunadamente eso no es suficiente.

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 tarjeta SIM) devolvieron un valor para TelephonyManager.getSimSerialNumber()
  3. Todos los dispositivos CDMA devolvieron un valor nulo para getSimSerialNumber() (como se esperaba)
  4. Todos los dispositivos con una cuenta de Google agregada devolvieron un valor para ANDROID_ID
  5. Todos los dispositivos CDMA devolvieron el mismo valor (o la derivación del mismo valor) tanto para ANDROID_ID como para TelephonyManager.getDeviceId() , siempre que se haya agregado una cuenta de Google durante la configuración.
  6. Todavía no tuve la oportunidad de probar dispositivos GSM sin SIM, un dispositivo GSM sin cuenta de Google o ninguno de los dispositivos en modo avión.

Entonces, si quieres 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 podría ser útil marcar uno o más de estos identificadores, de modo que la cadena sea prácticamente única para el dispositivo, pero no identifique explícitamente el dispositivo real del usuario. Por ejemplo, usando String.hashCode() , combinado con un UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

podría 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 propiedades de TelephonyManager , así que agregue esto a su manifiesto:

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

libs de importación

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

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 codigo:

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 hay al menos una interfaz "wlan0", y el chip WI-FI. Este código funciona incluso cuando WI-FI no está activado.

PD: hay otras muchas interfaces que obtendrás de la lista que contiene MACS, pero esto puede cambiar entre teléfonos


La identificación de mac del dispositivo Android también es una identificación única, no cambiará, supongamos que si formateamos el dispositivo en sí, utilicemos el siguiente código para obtener la identificación de mac

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

Además, no olvide agregar los permisos apropiados en su AndroidManifest.xml

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

El siguiente código devuelve el número de serie del dispositivo usando 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) {

}

Para reducir el tiempo de inicio de su emulador, debe marcar "Desactivar animación de inicio" antes de iniciar el emulador. Consulte la documentación de Android .

Si en caso de que no lo sepa, no necesita cerrar el emulador cada vez que ejecuta / depura su aplicación. Si hace clic en ejecutar / depurar cuando ya está abierto, su archivo APK se cargará en el emulador y comenzará casi de inmediato. El emulador toma mucho tiempo solo cuando comenzó la primera vez.

Estos son algunos consejos para acelerar el emulador de Android: Cómo acelerar el emulador de Android hasta en un 400% .





android uniqueidentifier