web-dev-qa-db-fra.com

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

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

2466
Tyler

Settings.Secure#Android_ID retourne l'ID Android sous la forme 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); 
1807

UPDATE: depuis les dernières versions d'Android, de nombreux problèmes liés à Android_ID ont été résolus et j'estime que cette approche n'est plus nécessaire. S'il vous plaît jeter un oeil à 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 le Blog du développeur Android entrée que la réponse d'emmby liens (à savoir, générer et enregistrer une UUID#randomUUID() ).


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

Sur la base de mes tests de périphériques (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 que un compte Google a été ajouté lors de l'installation.
  6. Je n'ai pas encore eu la possibilité 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 suffira. 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 identificateurs, de sorte 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(), associé à 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 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 TelephonyManager, ajoutez 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;
1087
Joe

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


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

Problème principal: matériel vs logiciel

Matériel

  • Les utilisateurs peuvent modifier leur matériel, leur tablette Android ou leur téléphone. Par conséquent, des ID uniques basés sur le matériel ne sont pas une bonne idée pour TRACKING USERS
  • 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 mieux vouloir SUIVI D'UN UTILISATEUR INDIVIDUEL avec leur consentement est simplement de les connecter (rendre cette opération transparente en utilisant 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 the unique ID of build information (may overlap data - API < 9)
_

Merci à @stansult pour avoir posté toutes nos options (dans cette question de débordement de pile).

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

  • Email Email - Logiciel

    • L'utilisateur peut changer d'email - TRÈS INCORRECT
    • 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 du périphérique 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 (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 - Hardware (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 sur le périphérique.

Je sais qu’il n’existe aucun 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 une API 9 ou plus, il est garanti que cela est unique du fait du champ 'Build.SERIAL'.

SOUVENEZ-VOUS, techniquement, il ne manque que 0,5% environ des utilisateurs qui ont une API <9 . 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 fait 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.Android_ID' renvoie 'null', alors simplement l'ID renvoyé sera basé uniquement sur leur Android informations sur le périphérique. 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://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 annonces ET les services Google Play):

À partir de la console de Google Play Developer:

À 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

Implementation :

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.htmlhttp://developer.Android.com/reference/com/google/Android/gms/ ads/identifiant/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 d'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://fr.kioskea.net/faq/34732-Android-reset-your-advertising-id

J'ai essayé de référencer chaque lien pour lequel 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/

413
Jared Burrows

Comme Dave Webb le mentionne, le Android Developer Blog contient un article qui couvre cela. Leur solution préférée consiste à suivre les installations d'applications plutôt que de périphériques, ce qui fonctionnera bien dans 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 la version 2.2.
  • Autant que je sache, tous les appareils affectés ont le même Android_ID , qui est 9774d56d682e549c . Quel est également le même identifiant de périphérique que celui signalé par l'émulateur, btw.
  • Google pense que les OEM ont corrigé le problème pour bon nombre de leurs appareils, voire la plupart d'entre eux, mais j'ai pu vérifier qu'au début d'avril 2011, au moins, il était encore assez facile de trouver des appareils dotés de l'identifiant 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 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 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 lors des 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;
    }
}
322
emmby

Voici le code utilisé par Reto Meier dans la présentation 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 nuage (également décrit dans le message talk de Reto, vous devez avoir un identifiant qui se lie à un utilisateur et qui persiste après le nettoyage ou même le remplacement du périphérique. I prévoyez d’utiliser cela dans les analyses à venir (en d’autres termes, je n’ai pas encore fait ce travail :).

171
Anthony Nolan

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 appareils, ce serait bien.

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

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

99
Seva Alekseyev

Il y a des informations plutôt utiles ici.

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. ID Android (peut être nul, peut changer lors de la réinitialisation d'usine, peut être modifié sur un téléphone root)
  4. WLAN Adresse MAC chaîne (nécessite Android.permission.ACCESS_WIFI_STATE)
  5. BT Adresse MAC chaîne (appareils avec Bluetooth, nécessite Android.permission.BLUETOOTH)
81
stansult

Le blog officiel des développeurs Android contient désormais un article complet sur ce sujet, Identification des installations d'applications.

47
BoD

Sur Google I/O Reto Meier a publié une réponse précise sur la façon de procéder, qui devrait répondre au besoin de la plupart des développeurs de suivre les utilisateurs sur les installations. Anthony Nolan indique la direction dans sa réponse, mais je pensais écrire l'approche complète afin que les autres puissent facilement voir comment le faire (cela m'a pris un certain temps pour comprendre les détails).

Cette approche vous donnera un ID utilisateur anonyme et sécurisé qui sera persistant pour l'utilisateur sur différents appareils (en fonction du compte Google principal) et pour toutes les installations. L'approche de base consiste à générer un ID utilisateur aléatoire et à le stocker dans les préférences partagées des applications. Vous utilisez ensuite l'agent de sauvegarde de Google pour stocker les préférences partagées liées au compte Google dans le cloud.

Passons en revue l'approche complète. Tout d'abord, nous devons créer une sauvegarde pour nos références partagées à l'aide du service de sauvegarde Android. Commencez par enregistrer votre application via http://developer.Android.com/google/backup/signup.html.

Google vous fournira une clé de service de sauvegarde que vous devrez ajouter au manifeste. Vous devez également indiquer à l'application d'utiliser BackupAgent comme suit:

<application Android:label="MyApplication"
         Android:backupAgent="MyBackupAgent">
    ...
    <meta-data Android:name="com.google.Android.backup.api_key"
        Android:value="your_backup_service_key" />
</application>

Ensuite, vous devez créer l'agent de sauvegarde et lui dire d'utiliser l'agent auxiliaire pour les préférences partagées:

public class MyBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

Pour terminer la sauvegarde, vous devez créer une instance de BackupManager dans votre activité principale:

BackupManager backupManager = new BackupManager(context);

Enfin, créez un ID utilisateur, s'il n'existe pas déjà, et stockez-le dans les SharedPreferences:

  public static String getUserID(Context context) {
            private static String uniqueID = null;
        private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                MyBackupAgent.PREFS, Context.MODE_PRIVATE);
        uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
        if (uniqueID == null) {
            uniqueID = UUID.randomUUID().toString();
            Editor editor = sharedPrefs.edit();
            editor.putString(PREF_UNIQUE_ID, uniqueID);
            editor.commit();

            //backup the changes
            BackupManager mBackupManager = new BackupManager(context);
            mBackupManager.dataChanged();
        }
    }

    return uniqueID;
}

Cet ID utilisateur sera désormais persistant dans toutes les installations, même si l'utilisateur déplace le périphérique.

Pour plus d'informations sur cette approche, voir le discours de Reto .

Et pour plus de détails sur la mise en œuvre de l'agent de sauvegarde, voir Sauvegarde des données. Je recommande particulièrement la section du bas sur les tests, car la sauvegarde ne se produit pas instantanément. Par conséquent, pour tester, vous devez forcer la sauvegarde.

38
TechnoTony

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 fonctionnant sur tous les appareils Android Certains appareils ne possèdent pas de téléphone (par exemple, les tablettes) ou, pour une raison quelconque, vous ne souhaitez pas inclure l'autorisation READ_PHONE_STATE. Vous pouvez toujours lire des détails tels que la version ROM, le nom du fabricant, le type de CPU et d’autres détails matériels, qui vous seront utiles si vous souhaitez utiliser l’ID pour une vérification de 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 ajoutons deux autres devant (35) pour avoir le même identifiant de taille que l’IMEI (15 chiffres). Il y a d'autres possibilités ici, jetez simplement un coup d'œil à ces chaînes . Renvoie 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 Pocket Magic .)

34
Lenn Dolling

Le code suivant renvoie le numéro de série du périphérique à l'aide d'une API Android masquée. Mais, ce code ne fonctionne pas sur Samsung Galaxy Tab car "ro.serialno" n'est pas défini sur cet appareil.

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

}
34
Roman SL

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); 
22
Mohit Kanada

Un champ Série a été ajouté à la classe Build dans le niveau 9 de l'API (Android 2.3 - Pain d'épice). 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.

18
rony l

J'ajouterai une chose: j'ai l'une de ces situations uniques.

En utilisant:

deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.Android_ID);

Il s'avère que même si ma tablette G Viewsonic signale un DeviceID différent de Null, chaque tablette G indique le même nombre.

Cela rend intéressant de jouer à "Pocket Empires" qui vous donne un accès instantané au compte de quelqu'un basé sur le "unique" DeviceID.

Mon appareil n'a pas de radio cellulaire.

15
Tony Maro

Pour obtenir des instructions détaillées sur l'obtention d'un identifiant unique pour chaque périphérique Android à partir duquel l'application est installée, voir la publication officielle du blog des développeurs Android Identification des installations d'application.

Il semble que le meilleur moyen consiste à en créer un vous-même lors de l'installation et à le lire ensuite au redémarrage de l'application.

Personnellement, je trouve cela acceptable mais pas idéal. Aucun identifiant fourni par Android ne fonctionne dans tous les cas, car la plupart dépendent des états de la radio du téléphone (Wi-Fi activé/désactivé, cellulaire activé/désactivé, Bluetooth activé/désactivé). Les autres, comme Settings.Secure.Android_ID, doivent être implémentés par le fabricant et ne sont pas garantis comme étant uniques.

Voici un exemple d'écriture de données dans un fichier installation qui serait stocké avec toutes les autres données que l'application enregistre localement.

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

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" />
10
Android

L'ID de périphérique unique d'un périphérique Android OS sous forme de chaîne, à l'aide de TelephonyManager et 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.

9
Elenasys

Il existe de nombreuses approches différentes pour contourner ces problèmes de Android_ID (il peut parfois être null ou les périphériques d’un modèle spécifique renvoient toujours le même ID) avec les avantages et les inconvénients:

  • Implémentation d'un algorithme de génération d'identifiant personnalisé (basé sur des propriétés de périphérique censées être statiques et qui ne changeront pas -> qui sait)
  • Utilisation abusive d'autres identifiants tels que IMEI , numéro de série, adresse Wi-Fi/Bluetooth-MAC (ils n'existeront pas sur tous les appareils ou des autorisations supplémentaires deviennent nécessaires)

Je préfère moi-même utiliser une implémentation OpenUDID existante (voir https://github.com/ylechelle/OpenUDID ) pour Android (voir https://github.com/vieux/OpenUDID ). Il est facile à intégrer et utilise le Android_ID avec des solutions de secours pour les problèmes mentionnés ci-dessus.

8
Andreas Klöber

Mes deux cents - NB ceci est pour un ID unique de périphérique (err) - et non pour l'installation comme indiqué 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 ici et ici ). 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 levée (conformément aux bonnes pratiques de Java consistant à ne pas donner de sens à null). Ainsi, par exemple, j'ai d'abord le téléphone TELEPHONY - mais un bon choix par défaut serait le Android_ID beta:

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

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

7
Elzo Valugi

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

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;
}
7
Eng.Fouad

Une autre méthode consiste à utiliser /sys/class/Android_usb/Android0/iSerial dans une application sans aucune autorisation.

user@creep:~$ adb Shell ls -l /sys/class/Android_usb/Android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
user@creep:~$ adb Shell cat /sys/class/Android_usb/Android0/iSerial
0A3CXXXXXXXXXX5

Pour faire cela en Java, il suffit d'utiliser un FileInputStream pour ouvrir le fichier iSerial et lire les caractères. Assurez-vous simplement de l'envelopper dans un gestionnaire d'exceptions, car tous les périphériques ne possèdent pas ce fichier. 

Au moins les périphériques suivants sont connus pour avoir ce fichier lisible par tout le monde:

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

Vous pouvez également voir mon article de blog Fuite du numéro de série du matériel Android vers des applications non privilégiées où je discute des autres fichiers disponibles pour information.

6
insitusec

Plus spécifiquement, 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_ID semble être un bon choix pour un identifiant de périphérique unique. 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.

6
mumu123

J'utilise le code suivant pour obtenir la IMEI ou utilise Secure .Android_ID comme alternative, lorsque le périphérique 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);
6
Asaf Pinhassi

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. 

3 identifiants sont:
Pseudo-ID - Il est généré en fonction 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 chaîne longId. 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 "";
}

Pour la reconnaissance matérielle d'un périphérique Android spécifique, vous pouvez vérifier les adresses MAC.

vous pouvez le faire de cette façon:

dans AndroidManifest.xml

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

maintenant dans votre code:

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

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

Dans tous les appareils Android, leur interface est au moins "wlan0" et constitue la puce WI-FI . Ce code fonctionne même lorsque WI-FI n'est pas activé.

P.S . Il y a un tas d'autres interfaces que vous obtiendrez de la liste contenant MACS Mais cela peut changer entre les téléphones.

6
Ilan.b

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 l'exécution ARC, un nouvel Android_ID est généré pour chaque installation ( 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 avez 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 mes tests non scientifiques, cela prend 1 à 3 secondes si le périphérique est en ligne, et 0,5 à 1,0 seconde s'il est hors ligne (vraisemblablement le délai d'attente avant l'abandon et la 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 gênantes (selon votre application, bien sûr).

5
Tom

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

N'oubliez pas non plus d'ajouter les autorisations appropriées dans votre fichier AndroidManifest.xml

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

TelephonyManger.getDeviceId () Renvoie l'ID de périphérique unique, par exemple l'IMEI pour GSM et le MEID ou ESN pour les téléphones CDMA.

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

Mais je recommande d'utiliser:

Settings.Secure.Android_ID qui renvoie l'identifiant Android sous forme de chaîne hexagonale unique de 64 bits.

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

Parfois, TelephonyManger.getDeviceId () renvoie la valeur null. Par conséquent, pour assurer un identifiant unique, vous utiliserez cette méthode:

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

Google a maintenant un identifiant publicitaire .
Ceci peut également ê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 basées sur les centres d'intérêt dans les applications Google Play.

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

Plus d'infos @ develper.Android

Copiez-collez le code ici

HTH

4
Hertzel Guinness

1.Vous pouvez accéder à l'identifiant de l'appareil Android par le service gms. voir l'exemple donné ci-dessous,

private DeviceInfoProvider mDeviceInfo = new DeviceInfoProvider(Context)
String mDeviceId = DeviceInfoProvider.getDeviceId(Context);
Log.d("DEVICE_ID" , mDeviceId);

2.Utilisez le gestionnaire de téléphonie, qui fournit un identifiant unique (IMEI). Voir l'exemple

import Android.telephony.TelephonyManager;
import Android.content.Context;
// ...
TelephonyManager telephonyManager;
telephonyManager = (TelephonyManager) getSystemService(Context.
                TELEPHONY_SERVICE);
/*
* getDeviceId() returns the unique device ID.
* For example,the IMEI for GSM and the MEID or ESN for CDMA phones.
*/
String deviceId = telephonyManager.getDeviceId();
/*
* getSubscriberId() returns the unique subscriber ID,
*/
String subscriberId = telephonyManager.getSubscriberId();

Cela nécessite Android.permission.READ_PHONE_STATE à votre utilisateur, ce qui peut être difficile à justifier en suivant le type d'application que vous avez faite.

  1. Les appareils sans services de téléphonie, tels que les tablettes, doivent signaler un identifiant d'appareil unique disponible via Android.os.Build.SERIAL depuis Android 2.3 Gingerbread. Certains téléphones disposant de services téléphoniques peuvent également définir un numéro de série. Comme tous les appareils Android n’ont pas de numéro de série, cette solution n’est pas fiable.

  2. Sur un premier démarrage de périphérique, une valeur aléatoire est générée et stockée. Cette valeur est disponible via Settings.Secure.Android_ID. C’est un nombre 64 bits qui devrait rester constant pendant toute la durée de vie d’un périphérique. Android_ID semble un bon choix pour un identifiant unique, car il est disponible pour les smartphones et les tablettes. Pour récupérer la valeur, vous pouvez utiliser le code suivant,

    String androidId = Settings.Secure.getString (getContentResolver (), Settings.Secure.Android_ID);

Cependant, la valeur peut changer si une réinitialisation d'usine est effectuée sur le périphérique. Il existe également un bug connu avec un téléphone populaire d'un fabricant où chaque instance a le même Android_ID. Clairement, la solution n'est pas fiable à 100%.

  1. Utilisez UUID. Comme la plupart des applications doivent impérativement identifier une installation particulière et non un périphérique physique, il s'agit d'une bonne solution pour obtenir l'identifiant unique d'un utilisateur s'il souhaite utiliser la classe UUID. La solution suivante a été présentée par Reto Meier de Google dans une présentation Google I/O,

SharedPreferences sharedPrefs = context.getSharedPreferences( PREF_UNIQUE_ID, Context.MODE_PRIVATE); uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);

4
Kiran Maniya

Non recommandé car deviceId peut être utilisé comme suivi entre des mains tierces, mais c'est une autre façon.

@SuppressLint("HardwareIds")
private String getDeviceID() {
    deviceId = Settings.Secure.getString(getApplicationContext().getContentResolver(),
                    Settings.Secure.Android_ID);
    return deviceId;
}
3
Ege Kuzubasioglu

Je suis tombé sur cette question il y a plusieurs années et j'ai appris à mettre en œuvre une solution généralisée basée sur diverses réponses.

J'ai utilisé la solution généralisée pendant plusieurs années, dans un produit du monde réel. Cela me sert assez bien jusqu'à présent. Voici l'extrait de code, basé sur diverses réponses fournies.

Notez que getEmail retournera null la plupart du temps, car nous n’avons pas demandé la permission explicitement.

private static UniqueId getUniqueId() {
    MyApplication app = MyApplication.instance();

    // Our prefered method of obtaining unique id in the following order.
    // (1) Advertising id
    // (2) Email
    // (2) Android_ID
    // (3) Instance ID - new id value, when reinstall the app.

    ////////////////////////////////////////////////////////////////////////////////////////////
    // ADVERTISING ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    AdvertisingIdClient.Info adInfo = null;
    try {
        adInfo = AdvertisingIdClient.getAdvertisingIdInfo(app);
    } catch (IOException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesRepairableException e) {
        Log.e(TAG, "", e);
    }

    if (adInfo != null) {
        String aid = adInfo.getId();
        if (!Utils.isNullOrEmpty(aid)) {
            return UniqueId.newInstance(aid, UniqueId.Type.aid);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // EMAIL
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String email = Utils.getEmail();
    if (!Utils.isNullOrEmpty(email)) {
        return UniqueId.newInstance(email, UniqueId.Type.eid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // Android ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String sid = Settings.Secure.getString(app.getContentResolver(), Settings.Secure.Android_ID);
    if (!Utils.isNullOrEmpty(sid)) {
        return UniqueId.newInstance(sid, UniqueId.Type.sid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // INSTANCE ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String iid = com.google.Android.gms.iid.InstanceID.getInstance(MyApplication.instance()).getId();
    if (!Utils.isNullOrEmpty(iid)) {
        return UniqueId.newInstance(iid, UniqueId.Type.iid);
    }

    return null;
}

public final class UniqueId implements Parcelable {
    public enum Type implements Parcelable {
        aid,
        sid,
        iid,
        eid;

        ////////////////////////////////////////////////////////////////////////////
        // Handling Parcelable nicely.

        public static final Parcelable.Creator<Type> CREATOR = new Parcelable.Creator<Type>() {
            public Type createFromParcel(Parcel in) {
                return Type.valueOf(in.readString());
            }

            public Type[] newArray(int size) {
                return new Type[size];
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeString(this.name());
        }

        // Handling Parcelable nicely.
        ////////////////////////////////////////////////////////////////////////////
    }

    public static boolean isValid(UniqueId uniqueId) {
        if (uniqueId == null) {
            return false;
        }
        return uniqueId.isValid();
    }

    private boolean isValid() {
        return !org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) && type != null;
    }

    private UniqueId(String id, Type type) {
        if (org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) || type == null) {
            throw new Java.lang.IllegalArgumentException();
        }
        this.id = id;
        this.type = type;
    }

    public static UniqueId newInstance(String id, Type type) {
        return new UniqueId(id, type);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + id.hashCode();
        result = 31 * result + type.hashCode();
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof UniqueId)) {
            return false;
        }

        UniqueId uniqueId = (UniqueId)o;
        return this.id.equals(uniqueId.id) && this.type == uniqueId.type;
    }

    @Override
    public String toString() {
        return type + ":" + id;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Handling Parcelable nicely.

    public static final Parcelable.Creator<UniqueId> CREATOR = new Parcelable.Creator<UniqueId>() {
        public UniqueId createFromParcel(Parcel in) {
            return new UniqueId(in);
        }

        public UniqueId[] newArray(int size) {
            return new UniqueId[size];
        }
    };

    private UniqueId(Parcel in) {
        this.id = in.readString();
        this.type = in.readParcelable(Type.class.getClassLoader());
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(this.id);
        parcel.writeParcelable(this.type, 0);
    }

    // Handling Parcelable nicely.
    ////////////////////////////////////////////////////////////////////////////

    public final String id;
    public final Type type;
}

public static String getEmail() {
    Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
    AccountManager accountManager = AccountManager.get(MyApplication.instance());
    Account[] accounts = accountManager.getAccountsByType("com.google");
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    accounts = accountManager.getAccounts();
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    return null;
} 
2
Cheok Yan Cheng

Voici une réponse simple pour obtenir AAID, testé et testé correctement en juin 2019

 AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            String token = null;
            Info adInfo = null;
            try {
                adInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext());
            } catch (IOException e) {
                // ...
            } catch ( GooglePlayServicesRepairableException e) {
                // ...
            } catch (GooglePlayServicesNotAvailableException e) {
                // ...
            }
            String Android_id = adInfo.getId();
            Log.d("DEVICE_ID",Android_id);

            return Android_id;
        }

        @Override
        protected void onPostExecute(String token) {
            Log.i(TAG, "DEVICE_ID Access token retrieved:" + token);
        }

    };
    task.execute();

lire la réponse complète en détail ici :

2
Raj

Comprendre les identifiants uniques disponibles sur les appareils Android. Utilisez ce guide officiel.

Meilleures pratiques pour les identificateurs uniques:

IMEI, adresses Mac, ID d'instance, GUID, SSAID, ID de publicité, API Safety Net pour vérifier les périphériques.

https://developer.Android.com/training/articles/user-data-ids

2
Waheed Nazir

Juste un avertissement pour tous ceux qui liront à la recherche d’informations plus récentes. Avec Android O, la manière dont le système gère ces identifiants a été modifiée. 

https://Android-developers.googleblog.com/2017/04/changes-to-device-identifiers-in.html

tl; dr Serial nécessitera l’autorisation PHONE et l’identité Android changera pour différentes applications, en fonction du nom de leur package et de sa signature.

Google a également rédigé un document de Nice contenant des suggestions sur l'utilisation des identifiants matériel et logiciel.

https://developer.Android.com/training/articles/user-data-ids.html

1
wrecker

Normalement, j'utilise un identifiant unique de périphérique pour mes applications. Mais parfois, j'utilise IMEI. Les deux sont des numéros uniques.

obtenirIMEI(identifiant international d'équipement mobile)

public String getIMEI(Activity activity) {
    TelephonyManager telephonyManager = (TelephonyManager) activity
            .getSystemService(Context.TELEPHONY_SERVICE);
    return telephonyManager.getDeviceId();
}

pour obtenir identifiant unique de l'appareil

public String getDeviceUniqueID(Activity activity){
    String device_unique_id = Secure.getString(activity.getContentResolver(),
            Secure.Android_ID);
    return device_unique_id;
}
1
Zin Win Htet

Numéro de série est un identifiant unique disponible sur Android.os.Build.SERIAL.

public static String getSerial() {
    String serial = "";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        serial = Build.getSerial();
    }else{ 
        serial = Build.SERIAL;    
    }
    return serial;
}

Assurez-vous que vous disposez de READ_PHONE_STATE permission avant d'appeler getSerial ().

NOTE: - Il est Non disponible avec les appareils sans téléphonie (comme les tablettes wifi uniquement).

1
Shivam Agrawal

Pour obtenir un identifiant d'utilisateur, vous pouvez utiliser la bibliothèque de licences de Google Play.

Pour télécharger cette bibliothèque, ouvrez SDK Manager => SDK Tools. Le chemin d'accès aux fichiers de bibliothèque téléchargés est:

path_to_Android_sdk_on_votre_pc/extras/google/market_licensing/bibliothèque

Incluez la bibliothèque dans votre projet (vous pouvez simplement copier ses fichiers).

Ensuite, vous avez besoin de quelques implémentations de l'interface Policy (vous pouvez simplement utiliser l'un des deux fichiers de la bibliothèque: ServerManagedPolicy ou StrictPolicy).

L'identifiant de l'utilisateur vous sera fourni dans la fonction processServerResponse():

public void processServerResponse(int response, ResponseData rawData) {
    if(rawData != null) {
        String userId = rawData.userId
        // use/save the value
    }
    // ...
}

Ensuite, vous devez construire la LicenseChecker avec une règle et appeler la fonction checkAccess(). Utilisez MainActivity.Java comme exemple de procédure. MainActivity.Java se trouve dans ce dossier:

path_to_Android_sdk_on_votre_pc/extras/google/marché_licensing/échantillon/src/com/exemple/Android/marché/licence

N'oubliez pas d'ajouter l'autorisation CHECK_LICENSE à votre AndroidManifest.xml.

En savoir plus sur la bibliothèque de licences: https://developer.Android.com/google/play/licensing

0
Vitaly Zinchenko
String SERIAL_NUMER = Build.SERIAL;

Renvoie NUMÉRO DE SÉRIE sous la forme d'une chaîne unique dans chaque appareil. 

0
Jeffy

Afin d'inclure Android 9 je n'ai qu'une idée qui puisse encore fonctionner, qui (probablement) n'enfreint aucun terme, nécessite des autorisations et fonctionne sur plusieurs installations et applications. 

Les empreintes digitales impliquant un serveur doivent être capables d'identifier un périphérique de manière unique . La combinaison d'informations sur le matériel + les applications installées et les temps d'installation devraient faire l'affaire. Les premières heures d’installation ne changent pas sauf si une application est désinstallée puis réinstallée. Mais cela devrait être fait pour toutes les applications sur l'appareil afin de ne pas pouvoir identifier l'appareil (c'est-à-dire après une réinitialisation d'usine). 

Voici comment je m'y prendrais:

  1. Extrayez les informations sur le matériel, les noms des packages d’application et les premières heures d’installation. 

Voici comment extraire toutes les applications d’Android (aucune autorisation requise):

final PackageManager pm = application.getPackageManager();
List<ApplicationInfo> packages = 
pm.getInstalledApplications(PackageManager.GET_META_DATA);

for (ApplicationInfo packageInfo : packages) {
    try {
        Log.d(TAG, "Installed package :" + packageInfo.packageName);
        Log.d(TAG, "Installed :" + pm.getPackageInfo(packageInfo.packageName, 0).firstInstallTime);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
}
  1. Vous voudrez peut-être créer un hachage de chaque combinaison de nom de paquet et d'horodatage d'installation avant de l'envoyer au serveur, car il peut s'agir ou non de ce que votre entreprise a installé sur le périphérique.
  2. Certaines applications (beaucoup en fait) sont des applications système. Celles-ci auront probablement le même horodatage d'installation, correspondant à la dernière mise à jour du système après une réinitialisation d'usine. Parce qu'ils ont le même horodatage d'installation, ils ne peuvent pas être installés par l'utilisateur et peuvent être filtrés.
  3. Envoyez les informations au serveur et laissez-le chercher la correspondance la plus proche parmi les informations précédemment stockées. Vous devez définir un seuil lors de la comparaison avec des informations de périphérique précédemment stockées au fur et à mesure que les applications sont installées et désinstallées. Mais ce que je suppose, c’est que ce seuil peut être très bas, car tout nom de package et toute combinaison d’horodatage lors de la première installation sera unique pour un appareil et les applications ne sont pas si fréquemment installées et désinstallées. Avoir plusieurs applications augmente simplement la probabilité d'être unique. 
  4. Renvoie l'identifiant unique généré pour la correspondance ou génère un identifiant unique, stocke-le avec les informations du périphérique et renvoie ce nouvel identifiant.

NB: Ceci est une méthode non testée et non prouvée! Je suis convaincu que cela fonctionnera, mais je suis également à peu près sûr que si cela réussit, ils le fermeront d'une manière ou d'une autre. 

0
Jens Vesti

Obtenez l'ID de périphérique une seule fois, puis stockez-le dans une base de données ou un fichier. Dans ce cas, s'il s'agit du premier démarrage de l'application, elle génère un ID et le stocke. La prochaine fois, il ne faudra que l'identifiant stocké dans le fichier.

0
El Jazouli

Si vous ajoutez:

Settings.Secure.getString(context.contentResolver,
    Settings.Secure.Android_ID)

Android Lint vous donnera l'avertissement suivant:

L'utilisation de getString pour obtenir les identificateurs de périphérique n'est pas recommandée. Informations de contrôle: L'utilisation de ces identificateurs de périphérique n'est pas recommandée, sauf pour la prévention des fraudes de grande valeur et les cas d'utilisation de la téléphonie avancée. Pour les cas d'utilisation de publicité, utilisez AdvertisingIdClient $ Info # getId et pour l'analyse, utilisez InstanceId # getId.

Donc, vous devriez éviter d'utiliser ceci.

Comme mentionné dans documentation pour les développeurs Android :

1: Évitez d’utiliser des identifiants matériels.

Dans la plupart des cas d'utilisation, vous pouvez éviter d'utiliser des identificateurs matériels, tels que SSAID (Android ID) et IMEI, sans limiter les fonctionnalités requises.

2: utilisez uniquement un identifiant de publicité pour les cas d'utilisation de profilage d'utilisateur ou d'annonce.

Lorsque vous utilisez un identifiant publicitaire, respectez toujours les choix des utilisateurs en matière de suivi des annonces. Assurez-vous également que l'identifiant ne peut pas être connecté à des informations d'identification personnelle (PII) et évitez de mettre en parallèle les réinitialisations d'ID de publicité.

3: Utilisez un ID d'instance ou un GUID enregistré de manière privée pour tous les autres cas d'utilisation, à l'exception de la prévention des fraudes de paiement et de la téléphonie.

Pour la grande majorité des cas d'utilisation non publicitaires, un ID d'instance ou GUID devrait suffire.

4: Utilisez des API adaptées à votre cas d'utilisation afin de minimiser les risques pour la confidentialité.

Utilisez l'API DRM pour la protection de contenu de grande valeur et les API SafetyNet pour la protection contre les abus. Les API SafetyNet constituent le moyen le plus simple de déterminer si un périphérique est authentique sans encourir de risque pour la confidentialité.

0
Malwinder Singh

Pour être complet, voici comment vous pouvez obtenir la Id dans Xamarin.Android et C #:

var id = Settings.Secure.GetString(ContentResolver, Settings.Secure.AndroidId);

Ou si vous n'êtes pas dans une Activity:

var id = Settings.Secure.GetString(context.ContentResolver, Settings.Secure.AndroidId);

context est le passé dans le contexte.

0
Martin Zikmund