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


115

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


2
Не забудьте добавить android: name = "android.permission.READ_PHONE_STATE" в свой манифест
Майкл Сильвеус


Если вы хотите получить уникальный идентификатор без каких-либо разрешений, вы можете использовать эту библиотеку для создания уникального идентификатора для каждого устройства с помощью Identity.getDeviceId (контекст) или идентификатора для установки вашего приложения через Identity.getInstallationId (контекст) .
caw

Ответы:


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

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

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


@Hasemam Это не работает для меня, выдает ошибку "Force Close"
Пареш Майани

23
@Hasemam теперь работает нормально после добавления разрешения <uses-permission android: name = "android.permission.READ_PHONE_STATE"> </uses-permission> в файл androidManifest.xml.
Пареш Майани,

23
В официальном блоге разработчиков Android есть несколько советов по использованию этого идентификатора: android-developers.blogspot.com/2011/03/…
Дэвид Снабел-Коун

8
А как насчет планшетов на базе Android, помимо микроволновки? :)
ajacian81

21
Этого метода следует избегать, он будет работать на телефонах, но не будет работать на устройствах без телефонного чипа (например, планшеты). Начиная с 2.3 вы можете использовать android.os.Build.SERIAL, но посмотрите блог разработчика, предложенный @DavidCaunt.
Джон Митчелл

71

Как упоминает Дэйв Уэбб, в блоге разработчиков Android есть статья об этом.

Я поговорил с кем-то в 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'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;
    }
}

1
Какие разрешения необходимы приложению, чтобы использовать это?
Дэйв Л.

1
<uses-permission android: name = "android.permission.READ_PHONE_STATE"> </uses-permission>
Габриель

1
@ ef2011 это шаблон блокировки с двойной проверкой: en.wikipedia.org/wiki/Double-checked_locking
emmby

3
Спасибо за публикацию. Но что помешает кому-то с рутированным телефоном просто отредактировать device_id.xml, чтобы ввести новый UUID по своему выбору? (то есть, чтобы обойти проверку «бесплатной пробной версии»). Не было бы лучше, если бы класс сохранял значение только в файле предпочтений, если ему приходится прибегать к методу случайного идентификатора? В противном случае нет необходимости сохранять его между запусками приложения; это более безопасно для повторной генерации.
Carlos P

1
«ANDROID_ID» является предпочтительным решением ». Обратите внимание, что ANDROID_ID больше не однозначно идентифицирует устройство: stackoverflow.com/a/13465373/150016
Tom

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

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


7
это просто дает мне то же значение, что и значение, которое я получаю с android.os.Build.SERIAL
josephus

Я ошибаюсь, или этот серийный номер одинаков на всех устройствах с конкретным пользовательским ПЗУ? Серийный номер моего устройства (в программе запуска устройств eclipse) показывает 01234567890ABC для телефона с настраиваемым ПЗУ.
Peterdk 08

@Peterdk на моем устройстве с cyanogen-9 оба метода (pre andy-9, как в ответе, и более простой, доступный от andy-9 on) сообщают правильный s / n (такой же, как на наклейке производителя). Однако это может зависеть от конкретной пользовательской версии ROM. Какую прошивку / версию вы используете?
morgwai 08

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

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


@Paresh Mayani, Трудно сказать, в чем может быть проблема, не глядя на код. Мое единственное предположение - это то, что getContentResolverвозвращается null. Однако, возможно, стоит задать вопрос и опубликовать свой код.
Энтони Форлони,

4
Этот идентификатор поступает из учетной записи Google, связанной с телефоном. В симуляторе его обычно нет. В настоящем телефоне его тоже может не быть. Кроме того, это задокументировано как «может измениться после сброса настроек», и это может быть изменено произвольно в любое время на рутированном телефоне. Используйте на свой риск. Нет хорошей альтернативы - другие предварительные идентификаторы устройств либо не доступны повсеместно, либо не уникальны, либо и то, и другое. См. Другие ответы на оставшуюся часть этой печальной истории.
Сева Алексеев

14

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

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

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

  • MAC-адрес
  • Серийный номер
  • ANDROID_ID

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


+1, привет, Дэйв, спасибо за разъяснения, потому что прямо сейчас я разрабатываю приложение для планшета, где мне нужно иметь уникальный идентификатор устройства Android, так что я должен использовать, чтобы получить уникальное планшетное устройство Android?
Пареш Майани

12

Чтобы получить простой номер, который является уникальным для устройства и постоянным на протяжении всего его срока службы (за исключением восстановления заводских настроек или взлома), используйте Settings.Secure.ANDROID_ID .

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

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

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

прямой ответ !!
Фарис Фэрис

Build.SERİAL устарел в java
Eyyüp Alkış

7

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

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

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


6

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

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

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

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

  3. Согласно факту (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 (не раскрывается, и я не знаю, какой бренд это тоже, наверное, Самсунг).

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


5

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

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

Давайте рассмотрим полный подход. Сначала нам нужно создать резервную копию наших SharedPreferences с помощью Android Backup Service. Начните с регистрации своего приложения по этой ссылке: 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>

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

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 Я особенно рекомендую раздел внизу, посвященный тестированию, поскольку резервное копирование делает не происходит мгновенно, поэтому для тестирования вам нужно принудительно выполнить резервное копирование.


2

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

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

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

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

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

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


Спасибо, что разместили свой ответ! Не забудьте внимательно прочитать FAQ по саморекламе . Также обратите внимание, что необходимо публиковать отказ от ответственности каждый раз, когда вы ссылаетесь на свой собственный сайт / продукт.
Эндрю Барбер

1

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

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

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

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

1

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

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:

Определение установок приложений


1

Build.SERIAL- самый простой способ, хотя и не совсем надежный, поскольку он может быть пустым или иногда возвращать другое значение ( доказательство 1 , доказательство 2 ), чем то, которое вы можете увидеть в настройках вашего устройства.

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

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

0

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

String deviceID = Build.SERIAL;


AFAIK, это изменится после обновления ОС устройства, например, с 4.4.2 на 4.4.4 или что-то еще.
Ден Дробязко

-1

Я нашел пример класса, опубликованный выше @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'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) || (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'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;
    }

Помещение идентификатора в общие настройки ставит под угрозу исходную цель, чтобы получить действительно уникальный идентификатор. Например, если вы хотите использовать этот идентификатор в качестве ключа для некоторых ограничений, вы будете облажались, когда опытные пользователи получат доступ к вашему общему файлу настроек. Его содержимое может быть скопировано, что означает ...
Юджин Векслер

есть еще одна ошибка в ответе MB и в вашем ... Если вы используете randomUUID в качестве идентификатора устройства и идентификатора приложения, он работает для всех устройств, независимо от того, являются ли они телефонами или нет, или являются ли они устройствами google exp или нет.
Фред Гротт

-2

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.