web-dev-qa-db-fra.com

Comment trouver le numéro de série de l'appareil Android?

Je dois utiliser un identifiant unique pour une application Android et je pensais que le numéro de série de l'appareil serait un bon candidat. Comment récupérer le numéro de série d'un appareil Android dans mon application?

113
Eno
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();

getSystemService est une méthode de la classe Activity. getDeviceID () renvoie le MDN ou le MEID de l'appareil en fonction de la radio utilisée par le téléphone (GSM ou CDMA).

Chaque appareil DOIT retourner une valeur unique ici (en supposant que ce soit un téléphone). Cela devrait fonctionner pour tous les appareils Android dotés d'un emplacement pour sim ou d'une radio CDMA. Vous êtes seul avec ce Android micro-ondes alimenté ;-)

102
haseman

Comme Dave Webb le mentionne, le Android Developer Blog contient un article qui couvre cela.

J'ai parlé à quelqu'un chez Google pour obtenir des éclaircissements supplémentaires sur quelques points. Voici ce que j'ai découvert qui n'est PAS mentionné dans l'article de blog susmentionné:

  • Android_ID est la solution préférée. Android_ID est parfaitement fiable sur les versions de 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 concernés ont le même Android_ID , ce 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 la plupart ou la plupart de leurs appareils, mais j'ai pu vérifier qu'au début d'avril 2011, au moins, il était encore assez facile de trouver des appareils 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).

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 static volatile 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;
    }
}
71
emmby
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) {
}

Ce code renvoie le numéro de série du périphérique à l'aide d'une API Android cachée.

32
Roman SL
String deviceId = Settings.System.getString(getContentResolver(),
                                Settings.System.Android_ID);

Bien qu'il ne soit pas garanti que l'ID Android sera un identifiant unique.

16
Anthony Forloney

Il y a n excellent article sur le Android blog du développeur qui en parle .

Il est déconseillé d'utiliser TelephonyManager.getDeviceId() car cela ne fonctionne pas sur Android appareils qui ne sont pas des téléphones tels que des tablettes. Il nécessite le READ_PHONE_STATE = permission et cela ne fonctionne pas de manière fiable sur tous les téléphones.

Au lieu de cela, vous pouvez utiliser l'un des éléments suivants:

  • Adresse Mac
  • Numéro de série
  • Android_ID

Cet article décrit les avantages et les inconvénients de chacun et mérite d'être lu pour vous permettre de déterminer lequel vous conviendrait le mieux.

14
Dave Webb

Pour un numéro simple propre à l'appareil et dont la durée de vie est constante (sauf réinitialisation d'usine ou piratage informatique), utilisez Settings.Secure.Android_ID .

String id = Secure.getString(getContentResolver(), Secure.Android_ID);

Pour utiliser le numéro de série du périphérique (celui indiqué dans "Paramètres système/À propos/Statut") s'il est disponible et revenir à Android ID:

String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.Android_ID);
12
Edward Brey

L'IMEI est bon mais ne fonctionne que sur Android appareils dotés d'un téléphone. Vous devriez également envisager de prendre en charge les tablettes ou autres appareils Android n'ayant pas de téléphone.

Vous avez des alternatives telles que: Construire des membres de la classe, BT MAC, WLAN MAC, ou même mieux - une combinaison de tous ces éléments.

J'ai expliqué ces détails dans un article de mon blog, voir: http://www.pocketmagic.net/?p=1662

7
radhoo

Puisque aucune réponse ne mentionne ici un ID parfait et irréprochable, qui est à la fois PERSISTENT via les mises à jour du système et existe dans TOUS les périphériques (principalement en raison du fait que Ce n’est pas une solution individuelle de Google), j’ai décidé de publier une méthode qui serait la meilleure solution en combinant deux des identificateurs disponibles et un contrôle permettant de les choisir au moment de l’exécution.

Avant le code, 3 faits:

  1. TelephonyManager.getDeviceId() (akaIMEI) ne fonctionnera pas bien ou ne fonctionnera pas du tout pour les appareils non-GSM, 3G, LTE, etc., mais renverra toujours un identifiant unique lorsqu'un matériel associé est présent. , même lorsqu'aucune carte SIM n'est insérée ou même lorsqu'il n'existe aucun emplacement pour carte SIM (certains constructeurs l'ont déjà fait).

  2. Depuis Gingerbread (Android 2.3) Android.os.Build.SERIAL doit exister sur tout appareil qui ne fournit pas IMEI , c'est-à-dire qui ne possède pas le matériel susmentionné. présent, conformément à la stratégie Android.

  3. En effet (2.), au moins un de ces deux identifiants uniques sera TOUJOURS présent et SERIAL peut être présent en même temps que IMEI.

Remarque: les faits (1.) et (2.) sont sur la base des déclarations de Google

SOLUTION

Avec les faits ci-dessus, on peut toujours avoir un identifiant unique en vérifiant s'il existe du matériel lié à IMEI, et revenir à SERIAL lorsqu'il ne l'est pas, car on ne peut pas vérifier si le SERIAL existant est valide. La classe statique suivante présente 2 méthodes pour vérifier cette présence et utiliser IMEI ou SERIAL:

import Java.lang.reflect.Method;

import Android.content.Context;
import Android.content.pm.PackageManager;
import Android.os.Build;
import Android.provider.Settings;
import Android.telephony.TelephonyManager;
import Android.util.Log;

public class IDManagement {

    public static String getCleartextID_SIMCHECK (Context mContext){
        String ret = "";

        TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

        if(isSIMAvailable(mContext,telMgr)){
            Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId());
            return telMgr.getDeviceId();

        }
        else{
            Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.Android_ID);

//          return Settings.Secure.Android_ID;
            return Android.os.Build.SERIAL;
        }
    }


    public static String getCleartextID_HARDCHECK (Context mContext){
        String ret = "";

        TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if(telMgr != null && hasTelephony(mContext)){           
            Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId() + "");

            return telMgr.getDeviceId();    
        }
        else{
            Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.Android_ID);

//          return Settings.Secure.Android_ID;
            return Android.os.Build.SERIAL;
        }
    }


    public static boolean isSIMAvailable(Context mContext, 
            TelephonyManager telMgr){

        int simState = telMgr.getSimState();

        switch (simState) {
        case TelephonyManager.SIM_STATE_ABSENT:
            return false;
        case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
            return false;
        case TelephonyManager.SIM_STATE_PIN_REQUIRED:
            return false;
        case TelephonyManager.SIM_STATE_PUK_REQUIRED:
            return false;
        case TelephonyManager.SIM_STATE_READY:
            return true;
        case TelephonyManager.SIM_STATE_UNKNOWN:
            return false;
        default:
            return false;
        }
    }

    static public boolean hasTelephony(Context mContext)
    {
        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if (tm == null)
            return false;

        //devices below are phones only
        if (Build.VERSION.SDK_INT < 5)
            return true;

        PackageManager pm = mContext.getPackageManager();

        if (pm == null)
            return false;

        boolean retval = false;
        try
        {
            Class<?> [] parameters = new Class[1];
            parameters[0] = String.class;
            Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
            Object [] parm = new Object[1];
            parm[0] = "Android.hardware.telephony";
            Object retValue = method.invoke(pm, parm);
            if (retValue instanceof Boolean)
                retval = ((Boolean) retValue).booleanValue();
            else
                retval = false;
        }
        catch (Exception e)
        {
            retval = false;
        }

        return retval;
    }


}

Je vous conseillerais d'utiliser getCleartextID_HARDCHECK. Si la réflexion ne colle pas dans votre environnement, utilisez plutôt la méthode getCleartextID_SIMCHECK, mais tenez compte du fait qu'elle doit être adaptée à vos besoins spécifiques en matière de présence sur la carte SIM.

PS : Veuillez noter que les constructeurs OEM ont réussi à mettre à jour SERIAL par rapport à la politique de Google (plusieurs appareils avec le même SÉRIE), et Google, comme indiqué, il y a au moins un cas connu dans un grand OEM (non divulgué et je ne sais pas de quelle marque il s'agit non plus, je suppose que c'est Samsung).

Disclaimer : Cela répond à la question initiale consistant à obtenir un ID de périphérique unique, mais le PO a introduit une ambiguïté en indiquant qu'il avait besoin d'un ID unique pour une application. Même si, dans de tels scénarios, Android_ID serait préférable, il ne fonctionnera pas après, par exemple, une sauvegarde titane d'une application via 2 installations ROM différentes (pouvant même être la même ROM). Ma solution maintient une persistance indépendante de toute réinitialisation flash ou usine, et échoue uniquement en cas d'altération IMEI ou SERIAL par le biais de piratages/mods matériels.

6
leRobot

Il y a des problèmes avec toutes les approches ci-dessus. Chez Google i/o, Reto Meier a publié une réponse précise sur la manière d’aborder cette question, ce qui devrait permettre à la plupart des développeurs de suivre les utilisateurs d’une installation à l’autre.

Cette approche vous donnera un ID utilisateur anonyme et sécurisé qui sera persistant pour l'utilisateur sur différents appareils (y compris les tablettes, sur le compte principal de Google) et sur les installations installées sur le même appareil. 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 à travers l'approche complète. Nous devons d’abord créer une sauvegarde pour nos références partagées à l’aide du service de sauvegarde Android. Commencez par enregistrer votre application via ce lien: http://developer.Android.com/google/backup/signup.html

Google vous donnera une clé de service de sauvegarde que vous devez 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 change de périphérique.

Pour plus d'informations sur cette approche, voir la présentation de Reto ici http://www.google.com/events/io/2011/sessions/Android-protips-advanced-topics-for-expert-Android-app-developers. html

Et pour plus de détails sur la mise en œuvre de l'agent de sauvegarde, voir le site du développeur ici: http://developer.Android.com/guide/topics/data/backup.html Je recommande particulièrement la section du en bas sur les tests car la sauvegarde ne se produit pas instantanément et pour tester vous devez forcer la sauvegarde.

5
TechnoTony

Une autre méthode consiste à utiliser/sys/class/Android_usb/Android0/iSerial dans une application sans 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 dans 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 ici: http://insitusec.blogspot.com/2013/01/leaking-Android-hardware-serial-number.html où je discute des autres fichiers disponibles pour Info.

2
insitusec

ID de périphérique unique de Android Device OS en tant que chaîne.

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 cette méthode suggérée par Google ::

Identification des installations d'application

1
Jorgesys

Build.SERIAL est le moyen le plus simple, bien que non totalement fiable car peut être vide ou renvoie parfois une valeur différente ( preuve 1 , preuve 2 ) que ce que vous pouvez voir dans les paramètres de votre appareil.

Il existe plusieurs façons d'obtenir ce numéro en fonction du fabricant de l'appareil et de la version de Android. J'ai donc décidé de compiler toutes les solutions possibles que je pouvais trouver dans un seul Gist . En voici une version simplifiée:

public static String getSerialNumber() {
    String serialNumber;

    try {
        Class<?> c = Class.forName("Android.os.SystemProperties");
        Method get = c.getMethod("get", String.class);

        serialNumber = (String) get.invoke(c, "gsm.sn1");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ril.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ro.serialno");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "sys.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = Build.SERIAL;

        // If none of the methods above worked
        if (serialNumber.equals(""))
            serialNumber = null;
    } catch (Exception e) {
        e.printStackTrace();
        serialNumber = null;
    }

    return serialNumber;
}
1
flawyte

Comme @haserman le dit:

TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();

Mais il est nécessaire d'inclure la permission dans le fichier manifeste:

<uses-permission Android:name="Android.permission.READ_PHONE_STATE"/>
1
cesards

Je sais que cette question est ancienne mais cela peut être fait en une seule ligne de code

String deviceID = Build.SERIAL;

0
MichaelStoddart