Как найти серийный номер Android-устройства?

Мне нужно использовать уникальный идентификатор для Android-приложения, и я думал, что серийный номер устройства будет хорошим кандидатом. Как получить серийный номер устройства Android в моем приложении?

Ответ 1

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

getSystemService - это метод класса Activity. getDeviceID() вернет MDN или MEID устройства в зависимости от того, какая радиоприемник использует телефон (GSM или CDMA).

Каждое устройство ДОЛЖНО вернуть уникальное значение здесь (при условии, что это телефон). Это должно работать на любом устройстве Android с SIM-слотом или CDMA-радио. Вы сами по себе с микрофоном с питанием от Android, -)

Ответ 2

Как упоминает Дейв Вебб, в Android Developer Blog есть статья, которая охватывает это.

Я поговорил с кем-то в Google, чтобы получить некоторые дополнительные разъяснения по нескольким пунктам. Вот что я обнаружил, что НЕ упоминается в вышеупомянутом сообщении в блоге:

  • ANDROID_ID является предпочтительным решением. ANDROID_ID отлично надежен в версиях Android <= 2.1 или >= 2.3. Только 2.2 имеет проблемы, упомянутые в сообщении.
  • Несколько устройств нескольких производителей подвержены ошибке ANDROID_ID в версии 2.2.
  • Насколько мне удалось определить, все уязвимые устройства те же ANDROID_ID, что 9774d56d682e549c. Это также тот же идентификатор устройства, о котором сообщает эмулятор, кстати.
  • Google полагает, что OEM-производители исправили проблему для многих или большинства своих устройств, но я смог проверить, что по состоянию на начало апреля 2011 года, по крайней мере, до сих пор довольно легко найти устройства с разбитым ANDROID_ID.

Основываясь на рекомендациях Google, я внедрил класс, который будет генерировать уникальный UUID для каждого устройства, используя ANDROID_ID в качестве семени, где это необходимо, при необходимости возвращаться к TelephonyManager.getDeviceId(), и если это не удастся, прибегая к случайному сгенерированный уникальный UUID, который сохраняется через перезагрузки приложений (но не для повторной установки приложения).

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 broken, in which case
                        // fallback on deviceId,
                        // unless it 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 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;
    }
}

Ответ 3

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

Этот код возвращает порядковый номер устройства с помощью скрытого API Android.

Ответ 4

String deviceId = Settings.System.getString(getContentResolver(),
                                Settings.System.ANDROID_ID);

Хотя, не гарантируется, что идентификатор Android будет уникальным идентификатором.

Ответ 5

Существует отличный пост в блоге разработчиков Android, обсуждающий это.

Он рекомендует использовать TelephonyManager.getDeviceId(), поскольку он не работает на устройствах Android, которые не являются телефонами, такими как планшеты, для этого требуется разрешение READ_PHONE_STATE, и оно не работает надежно на всех телефонах.

Вместо этого вы можете использовать одно из следующих действий:

  • Адрес Mac
  • Серийный номер
  • ANDROID_ID

В статье обсуждаются плюсы и минусы каждого, и это стоит прочитать, чтобы вы могли работать, что было бы лучше для вашего использования.

Ответ 6

Для простого номера, уникального для устройства и константы для его времени жизни (запрет factory reset или взлом), используйте Settings.Secure.ANDROID_ID.

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

Чтобы использовать серийный номер устройства (тот, который показан в разделе "Системные настройки/О программе/Статус" ), если он доступен, и вернуться к идентификатору Android:

String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);

Ответ 7

IMEI хорош, но работает только на устройствах Android с телефоном. Вы также должны рассмотреть возможность поддержки планшета или других устройств Android, у которых нет телефона.

У вас есть несколько альтернатив, например: Build class members, BT MAC, WLAN MAC или даже лучше - комбинация из всех этих.

Я объяснил эти подробности в статье в своем блоге: http://www.pocketmagic.net/?p=1662

Ответ 8

Так как нет ответа, здесь упоминается идеальный, отказоустойчивый идентификатор, который является ПОСТОЯННЫМ через обновления системы и существует во всех устройствах (в основном из-за того, что не существует индивидуального решения от Google), Я решил опубликовать метод, который является следующим лучшим, путем объединения двух доступных идентификаторов и проверки выбора между ними во время выполнения.

Перед кодом, 3 факта:

  • TelephonyManager.getDeviceId() (akaIMEI) не будет работать хорошо или вообще не для устройств, отличных от GSM, 3G, LTE и т.д., но всегда будет возвращать уникальный идентификатор, если имеется соответствующее оборудование, даже если SIM-карта не вставлена ​​или даже когда нет SIM-слота (некоторые OEM сделали это).

  • Так как Gingerbread (Android 2.3) android.os.Build.SERIAL должен существовать на любом устройстве, которое не предоставляет IMEI, т.е. не имеет вышеупомянутого оборудования в соответствии с политикой Android.

  • В силу факта (2.), хотя бы один из этих двух уникальных идентификаторов будет ВСЕГДА присутствовать, а SERIAL может присутствовать одновременно что IMEI есть.

Примечание. Факт (1.) и (2.) на основе утверждений Google

Решение

С приведенными выше фактами всегда можно получить уникальный идентификатор, проверяя, есть ли оборудование, связанное с IMEI, и возвращаться к SERIAL, когда это не так, поскольку нельзя проверить, действительно ли существующий SERIAL действителен. Следующий статический класс представляет 2 метода проверки такого присутствия и использования либо IMEI, либо 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;
    }


}

Я бы посоветовал использовать getCleartextID_HARDCHECK. Если отражение не вставляется в вашу среду, используйте вместо этого метод getCleartextID_SIMCHECK, но учтите, что он должен быть адаптирован к вашим конкретным потребностям в присутствии SIM-карты.

PS. Обратите внимание, что OEM смог выполнить проверку SERIAL в соответствии с политикой Google (несколько устройств с одним и тем же SERIAL), а Google, как указано, существует как минимум один известный случай в большом OEM (не раскрывается, и я не знаю, какой бренд он либо, я думаю, Samsung).

Отказ от ответственности. Это отвечает на исходный вопрос о получении уникального идентификатора устройства, но ОП представил неоднозначность, заявив, что ему нужен уникальный идентификатор для APP. Даже если для таких сценариев Android_ID будет лучше, он НЕ РАБОТАЕТ, скажем, Titanium Backup приложения через 2 разных установки ROM (может даже быть одним и тем же ПЗУ). Мое решение поддерживает постоянство, которое не зависит от флеш-памяти или factory reset, и будет терпеть неудачу только в том случае, если IMEI или SERIAL происходит с помощью хакеров/аппаратных мод.

Ответ 9

Есть проблемы со всеми вышеперечисленными подходами. В Google i/o Reto Meier выложили надежный ответ на вопрос о том, как подойти к этому, что должно удовлетворить большинство разработчиков, чтобы отслеживать пользователей через установки.

Этот подход даст вам анонимный безопасный идентификатор пользователя, который будет постоянным для пользователя на разных устройствах (включая планшеты на основе основной учетной записи Google) и через установки на том же устройстве. Основной подход - генерировать случайный идентификатор пользователя и сохранять его в общих настройках приложений. Затем вы используете агент Google для резервного копирования для хранения общих настроек, связанных с учетной записью Google в облаке.

Давайте рассмотрим полный подход. Сначала нам нужно создать резервную копию для наших SharedPreferences с помощью службы резервного копирования Android. Начните с регистрации своего приложения по этой ссылке: http://developer.android.com/google/backup/signup.html

Google предоставит вам ключ службы резервного копирования, который необходимо добавить в манифест. Вам также необходимо сообщить приложению, чтобы использовать BackupAgent следующим образом:

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

Затем вам нужно создать резервный агент и сообщить ему использовать вспомогательный агент для sharedpreferences:

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

Чтобы завершить резервное копирование, вам нужно создать экземпляр BackupManager в своей основной деятельности:

BackupManager backupManager = new BackupManager(context);

Наконец, создайте идентификатор пользователя, если он еще не существует, и сохраните его в 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;
}

Этот User_ID теперь будет постоянным во всех установках, даже если пользователь переключает устройства.

Для получения дополнительной информации об этом подходе см. раздел "Рето" здесь http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html

И для полной информации о том, как реализовать резервный агент, см. сайт разработчика здесь: http://developer.android.com/guide/topics/data/backup.html Я особенно рекомендую раздел внизу тестирования, так как резервное копирование не происходит мгновенно, поэтому для проверки необходимо принудительно выполнить резервное копирование.

Ответ 10

Другой способ - использовать /sys/class/android _usb/android0/iSerial в приложении без каких-либо разрешений.

[email protected]:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
[email protected]:~$ adb shell cat /sys/class/android_usb/android0/iSerial
0A3CXXXXXXXXXX5

Чтобы сделать это в java, просто используйте FileInputStream, чтобы открыть файл iSerial и прочитать символы. Просто убедитесь, что вы завернули его в обработчик исключений, потому что не все устройства имеют этот файл.

Известно, что, по крайней мере, следующие устройства имеют доступ к этому файлу:

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

Вы также можете увидеть мой блог здесь: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html, где я обсуждаю, какие другие файлы доступны для информации.

Ответ 11

Уникальный идентификатор устройства Android OS Device в качестве строки.

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

но я настоятельно рекомендую этот метод, предложенный Google::

Идентификация установок приложений

Ответ 12

Как говорит @haserman:

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

Но это необходимо, включая разрешение в файле манифеста:

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

Ответ 13

Я знаю, что этот вопрос старый, но это можно сделать в одной строке кода

String deviceID = Build.SERIAL;

Ответ 14

Я нашел класс примера, отправленный @emmby выше, чтобы стать отличной отправной точкой. Но у него есть несколько недостатков, как упоминалось другими плакатами. Главное заключается в том, что он не требует UUID для XML файла без необходимости и после этого всегда извлекает его из этого файла. Это открывает класс для простого взлома: любой, у кого есть встроенный телефон, может редактировать XML файл, чтобы дать себе новый UUID.

Я обновил код, чтобы он сохранялся только в XML, если это абсолютно необходимо (т.е. при использовании произвольно сгенерированного UUID), и рефакторизует логику в ответ на @Brill Pappin:

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 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 broken, in which case fallback on deviceId,
                        // unless it not available, then fallback on a random number which we store
                        // to a prefs file
                        try {
                             if ( "9774d56d682e549c".equals(androidId) || (androidId == null) ) {
                                final String deviceId = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE )).getDeviceId();

                                if (deviceId != null)
                                {
                                    uuid = UUID.nameUUIDFromBytes(deviceId.getBytes("utf8"));
                                }
                                else
                                {
                                    uuid = UUID.randomUUID();

                                    // Write the value out to the prefs file so it persists
                                    prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString() ).commit();
                                }
                            }
                            else
                            {
                                uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
                            } 
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }



                    }

                }
            }
        }

    }


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

Ответ 15

Да. Это серийный номер устройства, и он уникален. Таким образом, на уровне api 2.3 и выше вы можете использовать android.os.Build.ANDROID_ID, чтобы получить его. Для уровня ниже 2.3 API используйте TelephonyManager.getDeviceID().

вы можете прочитать это http://android-developers.blogspot.in/2011/03/identifying-app-installations.html