uniquely - uuid android




Existe-t-il un identifiant de périphérique Android unique? (20)

Les appareils Android ont-ils un identifiant unique et, le cas échéant, quel moyen simple d'y accéder via Java?


Dernière mise à jour: 6/2/15

Après avoir lu chaque article de sur la création d'un identifiant unique, du blog de développeur Google et de la documentation Android, je me sens comme si le "pseudo-identifiant" était la meilleure option possible.

Problème principal: matériel vs logiciel

Matériel

  • Les utilisateurs peuvent modifier leur matériel, leur tablette ou leur téléphone Android. Par conséquent, les identifiants uniques basés sur le matériel ne sont pas une bonne idée pour les utilisateurs de suivi
  • Pour TRACKING HARDWARE , c'est une excellente idée.

Logiciel

  • Les utilisateurs peuvent effacer / changer leur ROM s'ils sont enracinés
  • Vous pouvez suivre les utilisateurs sur différentes plates-formes (iOS, Android, Windows et Web)
  • Le meilleur moyen de suivre un utilisateur individuel avec son consentement est simplement de lui demander de se connecter (en toute transparence avec OAuth).

Répartition globale avec Android

- Garantir l'unicité (y compris les appareils rootés) pour les API> = 9/10 (99,5% des appareils Android)

- Pas d'autorisations supplémentaires

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

Merci à @stansult pour l’affichage de toutes nos options (dans cette question ).

Liste des options - raisons pour lesquelles / pourquoi ne pas les utiliser:

  • Email utilisateur - Logiciel

  • Numéro de téléphone de l'utilisateur - Logiciel

    • Les utilisateurs peuvent changer de numéro de téléphone - TRÈS improbable
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Matériel (téléphones uniquement, nécessite android.permission.READ_PHONE_STATE )

    • La plupart des utilisateurs détestent le fait qu'il soit dit "Appels téléphoniques" dans l'autorisation. Certains utilisateurs attribuent de mauvaises notes, car ils pensent que vous leur volez simplement des informations personnelles, alors que tout ce que vous voulez faire, c'est suivre les installations. Il est évident que vous collectez des données.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android ID - Matériel (peut être nul, peut changer lors de la réinitialisation d'usine, peut être modifié sur un appareil enraciné)

    • Puisqu'il peut être 'null', nous pouvons vérifier 'null' et changer sa valeur, mais cela signifie qu'il ne sera plus unique.
    • Si vous avez un utilisateur avec un périphérique réinitialisé aux valeurs d'usine, il se peut que la valeur ait été modifiée sur le périphérique racine. Il peut donc y avoir des entrées en double si vous suivez les installations de l'utilisateur.
  • Adresse MAC WLAN - Matériel (nécessite android.permission.ACCESS_WIFI_STATE )

    • Cela pourrait être la deuxième meilleure option, mais vous collectez et stockez toujours un identifiant unique qui provient directement d'un utilisateur. Ceci est évident que vous collectez des données.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Adresse MAC Bluetooth - Matériel (appareils avec Bluetooth, nécessite android.permission.BLUETOOTH )

    • La plupart des applications sur le marché n'utilisent pas Bluetooth. Par conséquent, si votre application n'utilise pas Bluetooth et que vous l'incluez, l'utilisateur peut devenir suspect.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-Unique ID - Logiciel (pour tous les appareils Android)

    • Très possible, peut contenir des collisions - Voir ma méthode affichée ci-dessous!
    • Cela vous permet d'avoir un identifiant "presque unique" de l'utilisateur sans rien prendre de privé. Vous pouvez créer votre propre ID anonyme à partir des informations de l'appareil.

Je sais qu'il n'existe pas de moyen "parfait" d'obtenir un identifiant unique sans utiliser les autorisations. Cependant, nous n'avons parfois que vraiment besoin de suivre l'installation de l'appareil. Lorsqu'il s'agit de créer un identifiant unique, nous pouvons créer un "pseudo-identifiant unique" basé uniquement sur les informations fournies par l'API Android sans utiliser d'autorisations supplémentaires. De cette façon, nous pouvons montrer le respect de l'utilisateur et essayer de lui offrir une bonne expérience.

Avec un pseudo-identifiant unique, vous ne rencontrez que le fait qu'il peut y avoir des doublons en raison du fait qu'il existe des périphériques similaires. Vous pouvez modifier la méthode combinée pour la rendre plus unique. Cependant, certains développeurs ont besoin de suivre les installations de périphériques et cela fera l'affaire ou la performance basée sur des périphériques similaires.

API> = 9:

Si leur périphérique Android est API 9 ou plus, cela est garanti d'être unique en raison du champ 'Build.SERIAL'.

N'OUBLIEZ PAS que , techniquement, environ 0,5% des utilisateurs ayant une API <9 sont absents. Vous pouvez donc vous concentrer sur le reste: 99,5% des utilisateurs!

API <9:

Si le périphérique Android de l'utilisateur est inférieur à API 9; espérons-le, ils n'ont pas effectué de réinitialisation d'usine et leur "Secure.ANDROID_ID" sera préservé ou non "null". (voir http://developer.android.com/about/dashboards/index.html )

Si tout échoue:

Si tout échoue, si l'utilisateur a une valeur inférieure à l'API 9 (inférieure à Gingerbread), a réinitialisé son appareil ou si 'Secure.ANDROIDID' renvoie 'null', alors simplement l'ID renvoyé sera uniquement basé sur les informations de son appareil Android. C'est là que les collisions peuvent se produire.

Changements:

  • La suppression de 'Android.SECURE_ID' en raison de réinitialisations d'usine peut entraîner une modification de la valeur
  • Edité le code pour changer sur l'API
  • Changé le pseudo

S'il vous plaît jeter un oeil à la méthode ci-dessous:

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

Nouveau (pour les applications avec annonces ET les services Google Play):

Depuis la console du développeur Google Play:

À compter du 1er août 2014, les règles du programme pour développeurs de Google Play exigent que tous les nouveaux téléchargements et mises à jour d'applications utilisent l'identifiant publicitaire au lieu de tout autre identifiant persistant à des fins publicitaires. Apprendre encore plus

Mise en œuvre :

Autorisation:

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

Code:

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

Source / Docs:

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

Important:

Il est prévu que l'ID de publicité remplace complètement l'utilisation existante d'autres identificateurs à des fins publicitaires (telles que l'utilisation de ANDROID_ID dans Settings.Secure) lorsque les services Google Play sont disponibles. Les cas où les services Google Play ne sont pas disponibles sont signalés par une exception GooglePlayServicesNotAvailableExot levée par getAdvertisingIdInfo ().

Attention, les utilisateurs peuvent réinitialiser:

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

J'ai essayé de faire référence à chaque lien que j'ai pris des informations. Si vous manquez et devez être inclus, veuillez commenter!

InstanceID des services Google Player

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


L'ID de périphérique unique d'un périphérique Android OS sous forme de chaîne, à l'aide de TelephonyManageret ANDROID_ID, est obtenu par:

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

Mais je recommande fortement une méthode suggérée par Google, voir Identification des installations d'application .


Comme Dave Webb le mentionne, le blog des développeurs Android contient un article sur ce sujet. Leur solution préférée consiste à suivre les installations d'applications plutôt que les appareils, et cela fonctionnera bien pour la plupart des cas d'utilisation. L'article de blog vous montrera le code nécessaire pour que cela fonctionne, et je vous recommande de le vérifier.

Cependant, l'article de blog continue pour discuter des solutions si vous avez besoin d'un identifiant de périphérique plutôt que d'un identifiant d'installation d'application. J'ai parlé à quelqu'un chez Google pour obtenir des éclaircissements supplémentaires sur quelques éléments au cas où vous en auriez besoin. Voici ce que j'ai découvert sur les identificateurs de périphérique, qui n'est PAS mentionné dans l'article de blog susmentionné:

  • ANDROID_ID est l'identifiant de périphérique préféré. ANDROID_ID est parfaitement fiable sur les versions d'Android <= 2.1 ou> = 2.3. Seulement 2.2 a les problèmes mentionnés dans le post.
  • Plusieurs périphériques de plusieurs fabricants sont affectés par le bogue ANDROID_ID dans 2.2.
  • Pour autant que je sache , tous les périphériques concernés ont le même ANDROID_ID , à savoir 9774d56d682e549c . Quel est également le même identifiant de périphérique que celui signalé par l'émulateur, btw.
  • Google pense que les constructeurs ont corrigé le problème pour la plupart de leurs appareils, mais j'ai pu vérifier qu'au début d'avril 2011, au moins, il était encore assez facile de trouver des appareils dont le ANDROID_ID était défectueux.

Sur la base des recommandations de Google, j'ai implémenté une classe qui générera un UUID unique pour chaque périphérique, en utilisant ANDROID_ID comme source, le cas échéant, en recourant à TelephonyManager.getDeviceId () si nécessaire, et en cas d'échec, en recourant à un UUID unique généré de manière aléatoire. qui persiste lors des redémarrages d'applications (mais pas pour les réinstallations d'applications).

Notez que pour les périphériques qui doivent se replier sur l'ID de périphérique, l'ID unique persistera après les réinitialisations d'usine. C'est quelque chose à prendre en compte. Si vous devez vous assurer qu'une réinitialisation d'usine réinitialisera votre ID unique, vous voudrez peut-être envisager de vous replier directement sur l'UUID aléatoire au lieu de l'ID de périphérique.

Encore une fois, ce code concerne un ID de périphérique, pas un ID d'installation d'application. Dans la plupart des situations, un ID d'installation d'application est probablement ce que vous recherchez. Mais si vous avez besoin d'un ID de périphérique, le code suivant fonctionnera probablement pour vous.

import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;

import java.io.UnsupportedEncodingException;
import java.util.UUID;

public class DeviceUuidFactory {

    protected static final String PREFS_FILE = "device_id.xml";
    protected static final String PREFS_DEVICE_ID = "device_id";
    protected volatile static UUID uuid;

    public DeviceUuidFactory(Context context) {
        if (uuid == null) {
            synchronized (DeviceUuidFactory.class) {
                if (uuid == null) {
                    final SharedPreferences prefs = context
                            .getSharedPreferences(PREFS_FILE, 0);
                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
                    if (id != null) {
                        // Use the ids previously computed and stored in the
                        // prefs file
                        uuid = UUID.fromString(id);
                    } else {
                        final String androidId = Secure.getString(
                            context.getContentResolver(), Secure.ANDROID_ID);
                        // Use the Android ID unless it's broken, in which case
                        // fallback on deviceId,
                        // unless it's not available, then fallback on a random
                        // number which we store to a prefs file
                        try {
                            if (!"9774d56d682e549c".equals(androidId)) {
                                uuid = UUID.nameUUIDFromBytes(androidId
                                        .getBytes("utf8"));
                            } else {
                                final String deviceId = (
                                    (TelephonyManager) context
                                    .getSystemService(Context.TELEPHONY_SERVICE))
                                    .getDeviceId();
                                uuid = deviceId != null ? UUID
                                    .nameUUIDFromBytes(deviceId
                                            .getBytes("utf8")) : UUID
                                    .randomUUID();
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                        // Write the value out to the prefs file
                        prefs.edit()
                                .putString(PREFS_DEVICE_ID, uuid.toString())
                                .commit();
                    }
                }
            }
        }
    }

    /**
     * Returns a unique UUID for the current android device. As with all UUIDs,
     * this unique ID is "very highly likely" to be unique across all Android
     * devices. Much more so than ANDROID_ID is.
     * 
     * The UUID is generated by using ANDROID_ID as the base key if appropriate,
     * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
     * be incorrect, and finally falling back on a random UUID that's persisted
     * to SharedPreferences if getDeviceID() does not return a usable value.
     * 
     * In some rare circumstances, this ID may change. In particular, if the
     * device is factory reset a new device ID may be generated. In addition, if
     * a user upgrades their phone from certain buggy implementations of Android
     * 2.2 to a newer, non-buggy version of Android, the device ID may change.
     * Or, if a user uninstalls your app on a device that has neither a proper
     * Android ID nor a Device ID, this ID may change on reinstallation.
     * 
     * Note that if the code falls back on using TelephonyManager.getDeviceId(),
     * the resulting ID will NOT change after a factory reset. Something to be
     * aware of.
     * 
     * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
     * directly.
     * 
     * @see http://code.google.com/p/android/issues/detail?id=10603
     * 
     * @return a UUID that may be used to uniquely identify your device for most
     *         purposes.
     */
    public UUID getDeviceUuid() {
        return uuid;
    }
}

Il y a des informations plutôt utiles here .

Il couvre cinq types d'identification différents:

  1. IMEI (uniquement pour les appareils Android utilisant le téléphone; nécessite android.permission.READ_PHONE_STATE )
  2. Pseudo-Unique ID (pour tous les appareils Android)
  3. Android ID (peut être nul, peut changer lors de la réinitialisation d'usine, peut être modifié sur le téléphone enraciné)
  4. Adresse MAC MAC WLAN (nécessite android.permission.ACCESS_WIFI_STATE )
  5. Chaîne d’ adresse MAC MAC (appareils avec Bluetooth, nécessite android.permission.BLUETOOTH )

Voici le code utilisé par Reto Meier dans la présentation de Google I / O cette année pour obtenir un identifiant unique pour l'utilisateur:

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 vous associez ceci à une stratégie de sauvegarde pour envoyer des préférences vers le cloud (également décrit dans l’ talk de Reto, vous devriez avoir un identifiant qui se connecte à un utilisateur et reste visible après le nettoyage ou le remplacement de l’appareil. Je prévois de l'utiliser. dans les analyses à venir (en d’autres termes, je n’ai pas encore fait ce travail :).


Vous pouvez également considérer l'adresse MAC de l'adaptateur Wi-Fi. Récupéré ainsi:

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

Nécessite l'autorisation android.permission.ACCESS_WIFI_STATE dans le manifeste.

Signalé comme étant disponible même lorsque le Wi-Fi n'est pas connecté. Si Joe de la réponse ci-dessus donne à celui-ci un essai sur ses nombreux périphériques, ce serait bien.

Sur certains appareils, il n'est pas disponible lorsque le Wi-Fi est désactivé.

REMARQUE: à partir d'Android 6.x, il renvoie une fausse adresse mac cohérente: 02:00:00:00:00:00


ID d'instance Google

Publié à I / O 2015; sur Android nécessite des services de jeu 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

Il semble que Google ait l'intention d'utiliser cet identifiant pour identifier les installations sous Android, Chrome et iOS.

Il identifie une installation plutôt qu'un périphérique, mais encore une fois, ANDROID_ID (qui est la réponse acceptée) n'identifie plus non plus les périphériques. Avec le runtime ARC, un nouvel ANDROID_ID est généré pour chaque installation (voir les détails ici ), tout comme ce nouvel ID d'instance. De plus, je pense que l’identification des installations (et non des périphériques) est ce que la plupart d’entre nous recherchent réellement.

Les avantages de l'instance ID

Il me semble que Google a l'intention de l'utiliser à cette fin (identifiant vos installations), il est multi-plateforme et peut être utilisé à plusieurs autres fins (voir les liens ci-dessus).

Si vous utilisez GCM, vous devrez éventuellement utiliser cet ID d'instance, car vous en aurez besoin pour obtenir le jeton GCM (qui remplace l'ancien ID d'enregistrement GCM).

Les inconvénients / problèmes

Dans l'implémentation actuelle (GPS 7.5), l'ID d'instance est extrait d'un serveur lorsque votre application le demande. Cela signifie que l’appel ci-dessus est un appel bloquant - lors de tests non scientifiques, cela prend 1 à 3 secondes si l’appareil est en ligne et 0,5 à 1,0 seconde s’il est hors ligne (vraisemblablement combien de temps il attend avant d’abandonner et de générer une identification aléatoire). Cela a été testé en Amérique du Nord sur Nexus 5 avec Android 5.1.1 et GPS 7.5.

Si vous utilisez l'ID aux fins auxquelles ils sont destinés - par exemple. authentification de l'application, identification de l'application, GCM - Je pense que ces 1 à 3 secondes pourraient être une gêne (en fonction de votre application, bien sûr).


MISE À JOUR : Depuis les dernières versions d'Android, de nombreux problèmes liés à ANDROID_ID ont été résolus et je pense que cette approche n'est plus nécessaire. S'il vous plaît jeter un oeil à la réponse d'Anthony .

Divulgation complète: mon application utilisait à l'origine l'approche ci-dessous, mais ne l'utilise plus. Nous utilisons maintenant l'approche décrite dans l'entrée android-developers.blogspot.com/2011/03/… laquelle emmby renvoie (en particulier, générer et enregistrer un UUID#randomUUID() ).

Il existe de nombreuses réponses à cette question, dont la plupart ne fonctionneront que "certaines" fois, et malheureusement cela ne suffit pas.

Basé sur mes tests d'appareils (tous les téléphones, dont au moins un n'est pas activé):

  1. Tous les périphériques testés ont renvoyé une valeur pour TelephonyManager.getDeviceId()
  2. Tous les appareils GSM (tous testés avec une carte SIM) ont renvoyé une valeur pour TelephonyManager.getSimSerialNumber()
  3. Tous les périphériques CDMA ont renvoyé la valeur null pour getSimSerialNumber() (comme prévu)
  4. Tous les appareils avec un compte Google ajouté ont renvoyé une valeur pour ANDROID_ID
  5. Tous les périphériques CDMA ont renvoyé la même valeur (ou une dérivation de la même valeur) pour ANDROID_ID et TelephonyManager.getDeviceId() - tant qu'un compte Google a été ajouté lors de la configuration.
  6. Je n'ai pas encore eu la chance de tester des appareils GSM sans carte SIM, un appareil GSM sans compte Google ajouté, ni aucun des appareils en mode avion.

Donc, si vous voulez quelque chose d'unique sur le périphérique lui-même, TM.getDeviceId() devrait suffire. Il est évident que certains utilisateurs sont plus paranoïaques que d'autres. Il peut donc être utile de hacher un ou plusieurs de ces identifiants afin que la chaîne reste pratiquement unique pour le périphérique, mais n'identifie pas explicitement le périphérique réel de l'utilisateur. Par exemple, en utilisant String.hashCode() , combiné avec 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();

peut aboutir à quelque chose comme: 00000000-54b3-e7c7-0000-000046bffd97

Cela fonctionne assez bien pour moi.

Comme Richard le mentionne ci-dessous, n'oubliez pas que vous avez besoin de l'autorisation pour lire les propriétés de TelephonyManager . Ajoutez donc ceci à votre manifeste:

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

importer des libs

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

Ajoutez le code ci-dessous dans le fichier de 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);

Ajouter dans AndroidManifest.xml:

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

En utilisant le code ci-dessous, vous pouvez obtenir l'ID de périphérique unique d'un périphérique Android OS sous forme de chaîne.

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

Je pense que c’est là un moyen sûr de construire un squelette pour une identité unique ... jetez-y un œil.

Pseudo-unique ID qui fonctionne sur tous les appareils Android Certains appareils ne disposent pas d'un téléphone (par exemple, des tablettes) ou pour une raison quelconque, vous ne souhaitez pas inclure l'autorisation READ_PHONE_STATE. Vous pouvez toujours lire des informations telles que la version de la ROM, le nom du fabricant, le type de CPU et d'autres informations matérielles, qui vous seront utiles si vous souhaitez utiliser l'ID pour la vérification d'une clé de série ou à d'autres fins générales. L'ID calculé de cette manière ne sera pas unique: il est possible de trouver deux périphériques avec le même ID (basés sur le même matériel et la même image ROM), mais les modifications dans les applications réelles sont négligeables. Pour cela, vous pouvez utiliser 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 plupart des membres de Build sont des chaînes, ce que nous faisons ici est de prendre leur longueur et de la transformer via modulo en un chiffre. Nous avons 13 chiffres de ce type et nous en ajoutons deux devant (35) pour avoir le même identifiant de taille que l’IMEI (15 chiffres). Il y a d'autres possibilités ici, jetez un coup d'œil à ces chaînes. Retourne quelque chose comme 355715565309247. Aucune autorisation spéciale n'est requise, ce qui rend cette approche très pratique.

(Extra info: La technique donnée ci-dessus a été copiée d'un article sur here .)


Le Mac ID du périphérique Android est également un identifiant unique. Cela ne changera pas si nous formatons le périphérique lui-même. Utilisez donc le code suivant pour obtenir le Mac ID.

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

Aussi, n'oubliez pas d'ajouter les autorisations appropriées dans votre AndroidManifest.xml

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

Voici comment je génère l'identifiant unique:

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

Google a maintenant un identifiant de publicité .
Cela peut aussi être utilisé, mais notez que:

L'ID de publicité est un ID unique, réinitialisable, spécifique à l'utilisateur.

et

permet aux utilisateurs de réinitialiser leur identifiant ou de désactiver les annonces par centres d'intérêt dans les applications Google Play.

Donc, bien que cet identifiant puisse changer, il semble que bientôt nous n’aurons peut-être pas le choix , cela dépend du but de cet identifiant.

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

Copiez-collez le code ici

HTH


Il y a plus de 30 réponses ici et certaines sont identiques et d'autres uniques. Cette réponse est basée sur peu de ces réponses. L'un d'eux est la réponse de @Lenn Dolling.

Il combine 3 ID et crée une chaîne hexadécimale de 32 chiffres. Cela a très bien fonctionné pour moi.

Les 3 ID sont les suivants:
Pseudo-ID - Il est généré sur la base des spécifications du périphérique physique
ANDROID_ID - Settings.Secure.ANDROID_ID
Adresse Bluetooth - Adresse de l' adaptateur Bluetooth

Il retournera quelque chose comme ceci: 551F27C060712A72730B0A0F734064B1

Remarque: vous pouvez toujours ajouter d'autres identifiants à la longIdchaîne. Par exemple, numéro de série. adresse de l'adaptateur wifi. IMEI. De cette façon, vous le rendez plus unique par appareil.

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

J'utilise le code suivant pour obtenir le IMEIou utiliser Secure. ANDROID_IDalternativement, lorsque l'appareil ne dispose pas des capacités du téléphone:

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

Mes deux cents - NB ceci est pour un ID unique de périphérique (err) - pas celui d'installation tel que discuté dans le blog des développeurs Android .

Il est à noter que la solution fournie par @emmby retombe dans un ID par application, car les références SharedPreferences ne sont pas synchronisées entre les processus (voir here et here ). J'ai donc évité tout cela.

Au lieu de cela, j’ai encapsulé les différentes stratégies pour obtenir un identifiant (de périphérique) dans une énumération - le fait de modifier l’ordre des constantes d’énum affecte la priorité des différentes manières d’obtenir l’ID. Le premier identifiant non nul est renvoyé ou une exception est renvoyée (conformément aux bonnes pratiques de Java qui ne donnent pas de sens à null). Ainsi, par exemple, j’ai d’abord le premier téléphone TELEPHONY - mais le bêta d’ ANDROID_ID serait un bon choix par défaut :

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

Plus précisément, Settings.Secure.ANDROID_ID. Il s'agit d'une quantité de 64 bits générée et stockée lors du premier démarrage du périphérique. Il est réinitialisé lorsque le périphérique est effacé.

ANDROID_IDsemble être un bon choix pour un identifiant unique de périphérique. Il y a des inconvénients: premièrement, il n'est pas fiable à 100% sur les versions d'Android antérieures à la version 2.2. (“Froyo”).De plus, il y a eu au moins un bogue largement observé dans un combiné populaire d'un grand fabricant, où chaque instance a le même ANDROID_ID.


Que diriez-vous de l' IMEI . C'est unique pour Android ou d'autres appareils mobiles.


Un champ Serial été ajouté à la Buildclasse dans l’API de niveau 9 (Android 2.3 - Gingerbread). La documentation indique qu'il représente le numéro de série du matériel. Ainsi, il devrait être unique, s'il existe sur le périphérique.

Je ne sais pas s'il est réellement pris en charge (= pas null) par tous les périphériques avec un niveau d'API> = 9 bien.





uniqueidentifier