Question Existe-t-il un identifiant d'appareil Android unique?


Les appareils Android ont-ils un identifiant unique et, dans l'affirmative, quel est le moyen le plus simple d'y accéder en utilisant Java?


2309
2018-05-07 00:47


origine


Réponses:


Settings.Secure#ANDROID_ID renvoie l'identifiant Android en tant que unique pour chaque utilisateur Chaîne hexagonale de 64 bits.

import android.provider.Settings.Secure;

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

1697
2018-05-07 00:49



METTRE À JOUR: Comme des versions récentes d'Android, de nombreux problèmes avec ANDROID_ID ont été résolus, et je crois 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 a utilisé l'approche ci-dessous à l'origine, mais n'utilise plus cette approche, et nous utilisons maintenant l'approche décrite dans le Blog développeur Android entrée que la réponse d'emmby liens vers (à savoir, générer et enregistrer un UUID#randomUUID()).


Il y a beaucoup de réponses à cette question, dont la plupart ne fonctionneront que «quelques fois», et malheureusement, cela ne suffit pas.

Basé sur mes tests de périphériques (tous les téléphones, dont au moins un n'est pas activé):

  1. Tous les appareils testés ont renvoyé une valeur pour TelephonyManager.getDeviceId()
  2. Tous les appareils GSM (tous testés avec une carte SIM) ont retourné une valeur pour TelephonyManager.getSimSerialNumber()
  3. Tous les périphériques CDMA ont renvoyé 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 dérivation de la même valeur) pour les deux ANDROID_ID et TelephonyManager.getDeviceId() - aussi longtemps que un compte Google a été ajouté lors de l'installation.
  6. Je n'ai pas encore eu l'occasion de tester des appareils GSM sans carte SIM, un appareil GSM sans compte Google ajouté, ou l'un des appareils en mode avion.

Donc, si vous voulez quelque chose d'unique à l'appareil lui-même, TM.getDeviceId()  devrait être suffisant. De toute évidence, certains utilisateurs sont plus paranoïaques que d'autres, il peut donc être utile de hacher un ou plusieurs de ces identifiants, de sorte que la chaîne reste virtuellement unique à l'appareil, 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();

pourrait entraîner quelque chose comme: 00000000-54b3-e7c7-0000-000046bffd97

Cela fonctionne assez bien pour moi.

Comme Richard mentionne ci-dessous, n'oubliez pas que vous avez besoin de la permission de lire le TelephonyManager propriétés, ajoutez-le à votre manifeste:

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

importer des bibliothèques

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

1056
2018-05-17 22:12



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


Après avoir lu tous les posts de Stack Overflow sur la création d'un identifiant unique, le blog du développeur Google et la documentation Android, j'ai l'impression que le pseudo ID est la meilleure option possible.

Problème principal: matériel vs logiciel

Matériel

  • Les utilisateurs peuvent changer leur matériel, tablette ou téléphone Android, donc les ID uniques basés sur le matériel ne sont pas de bonnes idées pour SUIVI DES UTILISATEURS
  • Pour SUIVI DE MATÉRIEL, C'est une bonne idée

Logiciel

  • Les utilisateurs peuvent effacer / modifier leur ROM s'ils sont enracinés
  • Vous pouvez suivre les utilisateurs sur plusieurs plates-formes (iOS, Android, Windows et Web)
  • Le meilleur vouloir SUIVRE UN UTILISATEUR INDIVIDUEL avec leur consentement est simplement de les connecter (rendre ceci transparent en utilisant OAuth)

Répartition globale avec Android

- Garantir l'unicité (inclure les appareils enracinés) pour l'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 toutes nos options (dans cette question Stack Overflow).

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

  • Email de l'utilisateur - Logiciel

    • L'utilisateur pourrait changer d'email - TRÈS improbable
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> ou
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" />  <uses-permission android:name="android.permission.READ_CONTACTS" /> (Comment obtenir l'adresse e-mail principale de l'appareil Android)
  • 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 (seulement les téléphones, les besoins android.permission.READ_PHONE_STATE)

    • La plupart des utilisateurs détestent le fait qu'il est dit "Appels téléphoniques" dans la permission. Certains utilisateurs donnent de mauvaises notes, car ils croient que vous leur volez simplement leurs informations personnelles, alors que tout ce que vous voulez vraiment faire est de suivre les installations des appareils. 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é)

    • Comme il peut être 'nul', 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 de réinitialisation d'usine, la valeur peut avoir été modifiée ou modifiée sur le périphérique enraciné, de sorte qu'il peut y avoir des doublons si vous suivez les installations de l'utilisateur.
  • Adresse MAC WLAN - Matériel (Besoins android.permission.ACCESS_WIFI_STATE)

    • Cela pourrait être la deuxième meilleure option, mais vous collectez et stockez toujours un identifiant unique provenant directement d'un utilisateur. C'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, besoins android.permission.BLUETOOTH)

    • La plupart des applications sur le marché n'utilisent pas Bluetooth, et donc si votre application n'utilise pas Bluetooth et que vous l'incluez, l'utilisateur pourrait 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 postée ci-dessous!
    • Cela vous permet d'avoir un identifiant «presque unique» de l'utilisateur sans prendre quoi que ce soit de privé. Vous pouvez créer votre propre identifiant anonyme à partir des informations sur le périphérique.

Je sais qu'il n'y a pas de façon «parfaite» d'obtenir un identifiant unique sans utiliser les autorisations; Cependant, nous avons parfois seulement besoin de suivre l'installation de l'appareil. Quand il s'agit de créer un identifiant unique, nous pouvons créer un pseudo identifiant unique basé uniquement sur les informations que l'API Android nous donne sans utiliser d'autorisations supplémentaires. De cette façon, nous pouvons montrer le respect de l'utilisateur et essayer d'offrir une bonne expérience utilisateur.

Avec un identifiant pseudo-unique, vous ne pouvez que constater qu'il peut y avoir des doublons basés sur le 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 dispositifs similaires.

API> = 9:

Si leur appareil Android est API 9 ou plus, cela est garanti d'être unique en raison du champ «Build.SERIAL».

RAPPELLES TOI, techniquement, vous ne ratez que 0,5% des utilisateurs qui ont une API <9. Vous pouvez donc vous concentrer sur le reste: c'est 99,5% des utilisateurs!

API <9:

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

Si tout le reste échoue:

Si tout le reste échoue, si l'utilisateur a inférieur à API 9 (inférieur à Gingerbread), a réinitialisé leur appareil ou 'Secure.ANDROID_ID' renvoie 'null', alors simplement l'ID retourné sera basé uniquement sur les informations de leur appareil Android. C'est là que les collisions peuvent arriver.

Changements:

  • En supprimant "Android.SECURE_ID" en raison des réinitialisations d'usine, la valeur peut changer
  • Editer 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://stackoverflow.com/a/4789483/950427
    // Only devices with API >= 9 have android.os.Build.SERIAL
    // http://developer.android.com/reference/android/os/Build.html#SERIAL
    // If a user upgrades software or roots their device, there will be a duplicate entry
    String serial = null;
    try {
        serial = android.os.Build.class.getField("SERIAL").get(null).toString();

        // Go ahead and return the serial for api => 9
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        // String needs to be initialized
        serial = "serial"; // some value
    }

    // Thanks @Joe!
    // https://stackoverflow.com/a/2853253/950427
    // Finally, combine the values we have found by using the UUID class to create a unique identifier
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

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

À partir de la console du développeur Google Play:

À compter du 1er août 2014, la stratégie du programme Google Play pour les développeurs   nécessite que toutes les nouvelles mises en ligne et mises à jour de l'application utilisent l'identifiant publicitaire   lieu de tout autre identificateur persistant à des fins publicitaires.   Apprendre encore plus

la mise en oeuvre:

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'identifiant publicitaire remplace complètement les   utilisation d'autres identifiants à des fins publicitaires (comme l'utilisation de ANDROID_ID   dans Settings.Secure) lorsque Google Play Services est disponible. Cas   lorsque les services Google Play sont indisponibles, ils sont signalés par un   GooglePlayServicesNotAvailableException levée par   getAdvertisingIdInfo ().

Attention, les utilisateurs peuvent réinitialiser:

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

J'ai essayé de référencer chaque lien dont j'ai pris l'information. Si vous manquez et devez être inclus, s'il vous plaît commenter!

ID de l'instance Google Player Services

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


364
2017-07-12 23:58



Comme le mentionne Dave Webb, le Android Developer Blog a un article ça couvre ça. Leur solution préférée est de suivre les installations d'applications plutôt que les appareils, et cela fonctionnera bien dans la plupart des cas d'utilisation. L'article du blog vous montrera le code nécessaire pour faire ce travail, et je vous recommande de le vérifier.

Cependant, le blog continue à discuter des solutions si vous avez besoin d'un identifiant d'appareil plutôt que d'un identifiant d'installation d'application. J'ai parlé avec quelqu'un à Google pour obtenir des précisions supplémentaires sur quelques éléments dans le cas où vous avez besoin de le faire. Voici ce que j'ai découvert à propos des identifiants de périphériques qui ne sont pas mentionnés dans le billet de blog mentionné ci-dessus:

  • 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.
  • Autant que j'ai pu déterminer, tous les appareils affectés ont le même ANDROID_ID, lequel est 9774d56d682e549c. Qui est également le même identifiant de périphérique signalé par l'émulateur, btw.
  • Google pense que les équipementiers ont corrigé le problème pour la plupart ou la plupart de leurs appareils, mais j'ai pu vérifier qu'au début du mois d'avril 2011, il est encore assez facile de trouver des appareils ayant un ANDROID_ID 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 en tant que germe le cas échéant, en revenant sur TelephonyManager.getDeviceId () si nécessaire, et si cela échoue, en recourant à un UUID unique généré aléatoirement qui persiste à travers les redémarrages d'applications (mais pas les réinstallations d'applications).

Notez que pour les appareils qui doivent se replier sur l'ID de l'appareil, l'identifiant unique VOLONTÉ persister dans les réinitialisations d'usine. C'est quelque chose à savoir. Si vous devez vous assurer qu'une réinitialisation d'usine réinitialisera votre ID unique, vous pouvez envisager de revenir directement à l'UUID aléatoire au lieu de l'ID de l'appareil.

Encore une fois, ce code est pour un ID d'appareil, pas un ID d'installation d'application. Dans la plupart des cas, l'ID d'installation d'une application est probablement ce que vous recherchez. Mais si vous avez besoin d'un identifiant d'appareil, 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;
    }
}

314
2018-04-11 19:06



Voici le code que Reto Meier a utilisé dans le Google I / O présentation 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 combinez cela avec une stratégie de sauvegarde pour envoyer des préférences au cloud (également décrit dans Reto parler, vous devriez avoir un identifiant qui lie à un utilisateur et reste après que l'appareil a été effacé, ou même remplacé. Je prévois d'utiliser cela dans l'analyse d'avenir (en d'autres termes, je n'ai pas encore fait ce petit peu :).


165
2017-10-28 13:19



Vous pouvez également prendre en compte 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 une permission android.permission.ACCESS_WIFI_STATE dans le manifeste.

Signalé être 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 appareils, 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 adresse mac fausse et cohérente: 02:00:00:00:00:00


97
2018-06-23 14:27



Il y a plutôt des informations utiles ici.

Il couvre cinq types d'ID différents:

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

78
2018-02-08 02:16



Le blog officiel des développeurs Android a maintenant un article complet à ce sujet, Identification des installations d'applications.


43
2018-04-06 07:36