uniqueidentifier device - C'è un ID univoco del dispositivo Android?




dove trova (25)

Esistono molti approcci diversi per aggirare tali ANDROID_IDproblemi (a nullvolte possono essere i dispositivi o un modello specifico restituiscono sempre lo stesso ID) con pro e contro:

  • Implementazione di un algoritmo di generazione di ID personalizzato (basato sulle proprietà del dispositivo che dovrebbero essere statiche e non cambierà -> chi lo sa)
  • Abuso di altri ID come IMEI , numero di serie, indirizzo Wi-Fi / Bluetooth-MAC (non saranno presenti su tutti i dispositivi o saranno necessarie ulteriori autorizzazioni)

Io stesso preferisco usare un'implementazione OpenUDID esistente (vedi https://github.com/ylechelle/OpenUDID ) per Android (vedi https://github.com/vieux/OpenUDID ). È facile da integrare e utilizza i ANDROID_IDfallback per i problemi sopra menzionati.

I dispositivi Android dispongono di un ID univoco e, in tal caso, qual è un modo semplice per accedervi utilizzando Java?


Google ora ha un ID pubblicità .
Questo può anche essere usato, ma nota che:

L'ID pubblicità è un ID ripristinabile specifico dell'utente, unico

e

consente agli utenti di reimpostare il proprio identificatore o disattivare gli annunci basati sugli interessi nelle app Google Play.

Quindi, sebbene questo ID possa cambiare, sembra che presto potremmo non avere una scelta , dipende dallo scopo di questo id.

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

Copia-incolla il codice qui

HTH


Un campo Serial stato aggiunto alla Buildclasse nel livello API 9 (Android 2.3 - Gingerbread). La documentazione dice che rappresenta il numero di serie dell'hardware. Quindi dovrebbe essere unico, se esiste sul dispositivo.

Non so se sia effettivamente supportato (= non null) da tutti i dispositivi con livello API> = 9.


Penso che questo sia un modo sicuro per costruire uno scheletro per un ID unico ... dai un'occhiata.

ID Pseudo-Unico, che funziona su tutti i dispositivi Android Alcuni dispositivi non hanno un telefono (ad esempio Tablet) o per qualche ragione, non si desidera includere l'autorizzazione READ_PHONE_STATE. È comunque possibile leggere i dettagli come la versione ROM, il nome del produttore, il tipo di CPU e altri dettagli hardware, che saranno adatti se si desidera utilizzare l'ID per un controllo della chiave seriale o per altri scopi generali. L'ID calcolato in questo modo non sarà univoco: è possibile trovare due dispositivi con lo stesso ID (basato sullo stesso hardware e immagine ROM) ma i cambiamenti nelle applicazioni del mondo reale sono trascurabili. A questo scopo puoi usare la classe 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 maggior parte dei membri di Build sono stringhe, quello che stiamo facendo qui è di prendere la loro lunghezza e trasformarla via modulo in una cifra. Abbiamo 13 cifre di questo tipo e ne aggiungiamo altre due nella parte anteriore (35) per avere lo stesso ID di dimensione dell'IMEI (15 cifre). Ci sono altre possibilità qui, state bene, date un'occhiata a queste stringhe. Restituisce qualcosa di simile 355715565309247. Non è richiesto alcun permesso speciale, rendendo questo approccio molto conveniente.

(Informazioni aggiuntive: la tecnica sopra riportata è stata copiata da un articolo su here .)


Inoltre, potresti prendere in considerazione l'indirizzo MAC dell'adattatore Wi-Fi. Recuperato così:

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

Richiede il permesso android.permission.ACCESS_WIFI_STATE nel manifest.

Segnalato per essere disponibile anche quando il Wi-Fi non è connesso. Se Joe dalla risposta sopra dà questa prova sui suoi molti dispositivi, sarebbe carino.

Su alcuni dispositivi, non è disponibile quando il Wi-Fi è disattivato.

NOTA: da Android 6.x, restituisce l'indirizzo mac falso coerente: 02:00:00:00:00:00


Ecco il codice che Reto Meier ha utilizzato nella presentazione di Google I / O quest'anno per ottenere un ID univoco per l'utente:

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

Se accetti questo con una strategia di backup per inviare le preferenze al cloud (descritto anche nel talk di Reto, dovresti avere un ID che si collega a un utente e resta in attesa dopo che il dispositivo è stato cancellato o addirittura sostituito. in analytics andando avanti (in altre parole, non ho ancora fatto quel po ':).


Utilizzando il codice riportato di seguito, è possibile ottenere l'ID dispositivo univoco di un dispositivo con sistema operativo Android come una stringa.

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


Che ne dici IMEI . Questo è unico per Android o altri dispositivi mobili.


Io uso il seguente codice per ottenere IMEIo usare Secure. ANDROID_IDin alternativa, quando il dispositivo non ha funzionalità telefoniche:

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

TelephonyManger.getDeviceId () Restituisce l'ID univoco del dispositivo, ad esempio l'IMEI per GSM e il MEID o ESN per i telefoni CDMA.

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

Ma io consiglio di usare:

Settings.Secure.ANDROID_ID che restituisce l'ID Android come una stringa esadecimale a 64 bit univoca.

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

Talvolta TelephonyManger.getDeviceId () restituirà null, quindi per assicurare un id univoco verrà utilizzato questo metodo:

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

ID mac dispositivo Android anche un ID univoco, non cambierà supponiamo se formifichiamo il dispositivo stesso in modo da utilizzare il seguente codice per ottenere ID mac

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

Inoltre, non dimenticare di aggiungere le autorizzazioni appropriate nel tuo AndroidManifest.xml

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

I miei due centesimi - NB questo è per un ID univoco (err) del dispositivo - non per l'installazione come discusso nel blog degli sviluppatori Android .

Da notare che la solution fornita da @emmby ricade in un ID per applicazione poiché le SharedPreferences non sono sincronizzate tra i processi (vedere here e here ). Così ho evitato del tutto.

Invece, ho incapsulato le varie strategie per ottenere un ID (dispositivo) in un enum - la modifica dell'ordine delle costanti enum influisce sulla priorità dei vari modi di ottenere l'ID. Viene restituito il primo ID non nullo o viene generata un'eccezione (come da buone pratiche Java di non dare un significato nullo). Ad esempio, per prima cosa ho il TELEPHONY, ma una buona scelta di default sarebbe il 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);
        }
    }
}

Per il riconoscimento hardware di uno specifico dispositivo Android è possibile controllare gli indirizzi MAC.

puoi farlo in questo modo:

in AndroidManifest.xml

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

ora nel tuo codice:

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

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

In ogni dispositivo Android la loro è almeno una "interfaccia wlan0" che è il chip WI-FI. Questo codice funziona anche quando WI-FI non è acceso.

PS Loro sono un sacco di altre interfacce che otterrete dalla lista contenente MACS, ma questo può cambiare tra i telefoni.


Aggiungi sotto il codice nel file di classe:

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

Aggiungi in AndroidManifest.xml:

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

Ci sono informazioni piuttosto utili here .

Comprende cinque diversi tipi di ID:

  1. IMEI (solo per dispositivi Android con l'uso del telefono; ha bisogno di android.permission.READ_PHONE_STATE )
  2. ID Pseudo-Univoco (per tutti i dispositivi Android)
  3. ID Android (può essere nullo, può cambiare al reset di fabbrica, può essere modificato sul telefono rooted)
  4. Stringa di indirizzo MAC WLAN (richiede android.permission.ACCESS_WIFI_STATE )
  5. Stringa di indirizzo MAC di BT (dispositivi con Bluetooth, richiede android.permission.BLUETOOTH )

Ci sono oltre 30 risposte qui e alcune sono uguali e alcune sono uniche. Questa risposta è basata su alcune di quelle risposte. Uno di questi è la risposta di @Lenn Dolling.

Combina 3 ID e crea una stringa esadecimale a 32 cifre. Ha funzionato molto bene per me.

3 ID sono:
Pseudo-ID - Viene generato in base alle specifiche fisiche del dispositivo
ANDROID_ID - Settings.Secure.ANDROID_ID
Indirizzo Bluetooth - Indirizzo adattatore Bluetooth

Restituirà qualcosa del genere: 551F27C060712A72730B0A0F734064B1

Nota: puoi sempre aggiungere altri ID alla longIdstringa. Ad esempio, numero di serie. indirizzo dell'adattatore wifi. IMEI. In questo modo lo renderai più unico per 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 "";
}

ID istanza di Google

Rilasciato all'I / O 2015; su Android richiede servizi di riproduzione 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

Sembra che Google intenda utilizzare questo ID per identificare le installazioni su Android, Chrome e iOS.

Identifica un'installazione piuttosto che un dispositivo, ma di nuovo, ANDROID_ID (che è la risposta accettata) ora non identifica più nemmeno i dispositivi. Con il runtime ARC viene generato un nuovo ANDROID_ID per ogni installazione ( dettagli qui ), proprio come questo nuovo ID istanza. Inoltre, penso che identificare le installazioni (non i dispositivi) sia ciò che la maggior parte di noi sta effettivamente cercando.

I vantaggi dell'ID istanza

Mi sembra che Google intenda utilizzarlo a tale scopo (identificando le tue installazioni), che sia multipiattaforma e possa essere utilizzato per una serie di altri scopi (vedi i link sopra).

Se utilizzi GCM, alla fine dovrai utilizzare questo ID di istanza perché ne hai bisogno per ottenere il token GCM (che sostituisce il vecchio ID di registrazione GCM).

Gli svantaggi / problemi

Nell'attuale implementazione (GPS 7.5) l'ID istanza viene recuperato da un server quando la tua app lo richiede. Ciò significa che la chiamata sopra è una chiamata bloccante - nel mio test non scientifico ci vogliono 1-3 secondi se il dispositivo è online e 0,5 - 1,0 secondi se non in linea (presumibilmente questo è il tempo che attende prima di arrendersi e generare un ID casuale). Questo è stato testato in Nord America su Nexus 5 con Android 5.1.1 e GPS 7.5.

Se si utilizza l'ID per gli scopi che intendono - ad es. autenticazione app, identificazione app, GCM - Penso che questo 1-3 secondi potrebbe essere un fastidio (a seconda dell'app, ovviamente).


Per istruzioni dettagliate su come ottenere un identificativo univoco per ciascun dispositivo Android dal quale è stata installata l'applicazione, vedere il post ufficiale del blog degli sviluppatori Android che android-developers.blogspot.com/2011/03/… .

Sembra che il modo migliore sia quello di crearne uno subito dopo l'installazione e successivamente leggerlo quando l'applicazione viene rilanciata.

Personalmente ritengo questo accettabile ma non ideale. Nessun identificatore fornito da Android funziona in tutte le istanze poiché la maggior parte dipende dagli stati radio del telefono (Wi-Fi on / off, cellulare on / off, Bluetooth on / off). Gli altri, come Settings.Secure.ANDROID_IDdevono essere implementati dal produttore e non sono garantiti per essere unici.

Di seguito è riportato un esempio di scrittura di dati in un file di installazione che verrebbe archiviato insieme ad altri dati che l'applicazione salva 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();
    }
}

AGGIORNAMENTO : A partire dalle versioni recenti di Android, molti dei problemi con ANDROID_ID sono stati risolti e credo che questo approccio non sia più necessario. Si prega di dare un'occhiata alla risposta di Anthony .

Completa divulgazione: la mia app ha utilizzato l'approccio di seguito in origine ma non utilizza più questo approccio e ora utilizziamo l'approccio delineato nella voce android-developers.blogspot.com/2011/03/… cui rimanda la risposta di emmby (ovvero, generazione e salvataggio di un UUID#randomUUID() ).

Ci sono molte risposte a questa domanda, molte delle quali funzioneranno solo "alcune" volte, e sfortunatamente non è abbastanza buona.

In base ai miei test sui dispositivi (tutti i telefoni, almeno uno dei quali non è attivato):

  1. Tutti i dispositivi testati hanno restituito un valore per TelephonyManager.getDeviceId()
  2. Tutti i dispositivi GSM (tutti testati con una SIM) hanno restituito un valore per TelephonyManager.getSimSerialNumber()
  3. Tutti i dispositivi CDMA hanno restituito null per getSimSerialNumber() (come previsto)
  4. Tutti i dispositivi con un account Google aggiunto hanno restituito un valore per ANDROID_ID
  5. Tutti i dispositivi CDMA hanno restituito lo stesso valore (o derivazione dello stesso valore) per ANDROID_ID e TelephonyManager.getDeviceId() , purché sia stato aggiunto un account Google durante l'installazione.
  6. Non avevo ancora la possibilità di provare i dispositivi GSM senza SIM, dispositivo GSM senza account Google aggiunto o nessuno dei dispositivi in ​​modalità aereo.

Quindi, se vuoi qualcosa di unico per il dispositivo stesso, TM.getDeviceId() dovrebbe essere sufficiente. Ovviamente alcuni utenti sono più paranoici di altri, quindi potrebbe essere utile usare l'hash 1 o più di questi identificatori, in modo che la stringa sia ancora virtualmente unica per il dispositivo, ma non identifichi esplicitamente il dispositivo reale dell'utente. Ad esempio, utilizzando String.hashCode() , combinato 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();

potrebbe comportare qualcosa come: 00000000-54b3-e7c7-0000-000046bffd97

Funziona abbastanza bene per me.

Come menzionato da Richard qui sotto, non dimenticare che hai bisogno dell'autorizzazione per leggere le proprietà di TelephonyManager , quindi aggiungi questo al tuo manifest:

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

librerie di importazione

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

Il seguente codice restituisce il numero di serie del dispositivo utilizzando un'API Android nascosta. Ma questo codice non funziona su Samsung Galaxy Tab perché "ro.serialno" non è impostato su questo 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) {

}

Ecco come sto generando l'ID univoco:

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

Un altro modo è quello di utilizzare /sys/class/android_usb/android0/iSerialin un'applicazione senza permessi di sorta.

[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

Per fare ciò in Java si usa semplicemente un FileInputStream per aprire il file iSerial e leggere i caratteri. Assicurati di averlo racchiuso in un gestore di eccezioni, perché non tutti i dispositivi hanno questo file.

Almeno i seguenti dispositivi sono noti per avere questo file leggibile a livello mondiale:

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

È anche possibile vedere il mio post sul blog Perdendo il numero di serie dell'hardware di Android in app non privilegiate in cui discuto di quali altri file sono disponibili per informazioni.


Ultimo aggiornamento: 6/2/15

Dopo aver letto tutti i post di sulla creazione di un ID univoco, il blog degli sviluppatori di Google e la documentazione di Android, mi sembra che lo "Pseudo ID" sia la migliore opzione possibile.

Problema principale: hardware vs software

Hardware

  • Gli utenti possono cambiare hardware, tablet Android o telefono, quindi ID univoci basati su hardware non sono buone idee per gli UTENTI DI TRACKING
  • Per TRACKING HARDWARE , questa è una grande idea

Software

  • Gli utenti possono cancellare / modificare la propria ROM se sono rootati
  • Puoi tenere traccia degli utenti su piattaforme diverse (iOS, Android, Windows e Web)
  • I migliori vogliono GUIDARE UN UTENTE INDIVIDUALE con il loro consenso è quello di averli semplicemente registrati (rendilo trasparente usando OAuth)

Ripartizione generale con Android

- Garantire univocità (includere dispositivi rooted) per API> = 9/10 (99,5% dei dispositivi Android)

- Nessuna autorizzazione aggiuntiva

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

Grazie a @stansult per aver pubblicato tutte le nostre opzioni (in questa domanda ).

Elenco di opzioni - ragioni per le quali / perché non usarle:

  • Email dell'utente - Software

    • L'utente potrebbe cambiare email - ALTAMENTE improbabile
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> o
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> ( Come ottenere l'indirizzo e-mail principale del dispositivo Android )
  • Numero di telefono dell'utente - Software

    • Gli utenti possono cambiare i numeri di telefono - ALTAMENTE improbabile
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Hardware (solo telefoni, ha bisogno di android.permission.READ_PHONE_STATE )

    • La maggior parte degli utenti odia il fatto che nell'autorizzazione sia indicato "Telefonate". Alcuni utenti danno valutazioni errate, perché credono che stai semplicemente rubando le loro informazioni personali, quando tutto ciò che vuoi veramente è monitorare le installazioni dei dispositivi. È ovvio che stai raccogliendo dati.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • ID Android - Hardware (può essere nullo, può cambiare al reset di fabbrica, può essere modificato su un dispositivo rooted)

    • Dal momento che può essere 'null', possiamo controllare 'null' e cambiarne il valore, ma questo significa che non sarà più univoco.
    • Se si dispone di un utente con un dispositivo di ripristino di fabbrica, il valore potrebbe essere stato modificato o modificato sul dispositivo rooted in modo che possano essere presenti voci duplicate se si monitorano le installazioni utente.
  • Indirizzo MAC WLAN - Hardware (richiede android.permission.ACCESS_WIFI_STATE )

    • Questa potrebbe essere la seconda opzione migliore, ma stai ancora raccogliendo e memorizzando un identificatore univoco che proviene direttamente da un utente. Questo è ovvio che stai raccogliendo dati.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Indirizzo MAC Bluetooth - Hardware (dispositivi con Bluetooth, richiede android.permission.BLUETOOTH )

    • La maggior parte delle applicazioni sul mercato non usa il Bluetooth, quindi se l'applicazione non usa il Bluetooth e questo è incluso, l'utente potrebbe diventare sospetto.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-Unique ID - Software (per tutti i dispositivi Android)

    • Molto possibile, potrebbe contenere collisioni - Vedi il mio metodo pubblicato qui sotto!
    • Ciò ti consente di avere un ID "quasi unico" dall'utente senza prendere nulla di privato. Puoi creare il tuo ID anonimo dalle informazioni del dispositivo.

So che non esiste un modo "perfetto" per ottenere un ID univoco senza utilizzare le autorizzazioni; tuttavia, a volte abbiamo solo bisogno di monitorare l'installazione del dispositivo. Quando si tratta di creare un ID univoco, è possibile creare un 'ID pseudo unico' basato esclusivamente su informazioni che l'API di Android ci offre senza utilizzare autorizzazioni aggiuntive. In questo modo, possiamo mostrare rispetto all'utente e cercare di offrire anche una buona esperienza utente.

Con un id pseudo-univoco, ti imbatti solo nel fatto che potrebbero esserci duplicati in base al fatto che esistono dispositivi simili. Puoi modificare il metodo combinato per renderlo più unico; tuttavia, alcuni sviluppatori devono monitorare le installazioni dei dispositivi e questo farà il trucco o le prestazioni in base a dispositivi simili.

API> = 9:

Se il loro dispositivo Android è API 9 o superiore, questo è garantito per essere univoco a causa del campo "Build.SERIAL".

RICORDA , tecnicamente stai perdendo solo lo 0,5% degli utenti che hanno API <9 . Quindi puoi concentrarti sul resto: questo è il 99,5% degli utenti!

API <9:

Se il dispositivo Android dell'utente è inferiore all'API 9; si spera che non abbiano fatto un reset di fabbrica e che il loro 'Secure.ANDROID_ID' sia conservato o non 'nullo'. (vedi http://developer.android.com/about/dashboards/index.html )

Se tutti gli altri falliscono:

Se tutto il resto fallisce, se l'utente ha un valore inferiore all'API 9 (inferiore a Gingerbread), ha ripristinato il proprio dispositivo o "Secure.ANDROID_ID" restituisce "null", quindi semplicemente l'ID restituito si baserà esclusivamente sulle informazioni del proprio dispositivo Android. Questo è dove possono accadere le collisioni.

I cambiamenti:

  • Rimosso "Android.SECURE_ID" a causa di ripristini di fabbrica potrebbe causare la modifica del valore
  • Modificato il codice da cambiare su API
  • Modificato lo pseudo

Si prega di dare un'occhiata al metodo qui sotto:

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

Novità (per app con annunci AND Google Play Services):

Dalla console dello sviluppatore di Google Play:

A partire dal 1 ° agosto 2014, le Norme del programma per gli sviluppatori di Google Play richiedono che tutti i nuovi caricamenti e aggiornamenti delle app utilizzino l'ID pubblicitario al posto di altri identificativi persistenti per scopi pubblicitari. Per saperne di più

Implementazione :

Autorizzazione:

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

Codice:

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

Fonte / Documenti:

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

Importante:

È inteso che l'ID pubblicità sostituisca completamente l'utilizzo esistente di altri identificatori per scopi pubblicitari (come l'utilizzo di ANDROID_ID in Settings.Secure) quando i servizi di Google Play sono disponibili. I casi in cui Google Play Services non è disponibile sono indicati da una GooglePlayServicesNotAvailableException lanciata da getAdvertisingIdInfo ().

Attenzione, gli utenti possono ripristinare:

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

Ho provato a fare riferimento a ogni link da cui ho preso informazioni. Se ti manca e devi essere incluso, per favore commenta!

ID istanza di Google Player Services

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


Il sistema di build Gradle è progettato per supportare scenari complessi nella creazione di applicazioni Android:

Multi-distribuzione : la stessa applicazione deve essere personalizzata per diversi clienti o aziende

Multi-apk: supporta la creazione di apk multipli per diversi tipi di dispositivi durante il riutilizzo di parti del codice





android uniqueidentifier