Существует ли уникальный идентификатор устройства Android? - PullRequest
2562 голосов
/ 07 мая 2010

Имеют ли устройства Android уникальный идентификатор, и если да, то какой простой способ получить к нему доступ с помощью Java?

Ответы [ 43 ]

7 голосов
/ 18 сентября 2013

Мои два цента - обратите внимание, это для уникального идентификатора устройства (err) - не установочного, как обсуждалось в блоге разработчиков Android .

Следует отметить, что решение , предоставляемое @emmby, использует идентификатор каждого приложения, поскольку SharedPreferences не синхронизируются между процессами (см. здесь и здесь ). Так что я вообще этого избежал.

Вместо этого я инкапсулировал различные стратегии получения идентификатора (устройства) в перечислении - изменение порядка перечисления констант влияет на приоритет различных способов получения идентификатора. Возвращается первый ненулевой идентификатор или генерируется исключение (в соответствии с хорошими практиками Java, не предусматривающими нулевого значения). Так, например, сначала у меня есть TELEPHONY, но хорошим выбором по умолчанию будет ANDROID_ID бета:

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 голосов
/ 08 марта 2017

Здесь более 30 ответов, и некоторые из них одинаковы, а некоторые уникальны. Этот ответ основан на нескольких из этих ответов. Одним из них является ответ @Lenn Dolling.

Он объединяет 3 идентификатора и создает 32-значную шестнадцатеричную строку. Это сработало очень хорошо для меня.

3 идентификатора:
Pseudo-ID - генерируется на основе спецификаций физического устройства
ANDROID_ID - Settings.Secure.ANDROID_ID
Адрес Bluetooth - Адрес адаптера Bluetooth

Будет возвращено что-то вроде этого: 551F27C060712A72730B0A0F734064B1

Примечание. Вы всегда можете добавить дополнительные идентификаторы в строку longId. Например, Серийный №. адрес адаптера Wi-Fi. IMEI. Таким образом, вы делаете его более уникальным для каждого устройства.

@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 "";
}
6 голосов
/ 01 сентября 2015

Для аппаратного распознавания определенного устройства Android вы можете проверить MAC-адреса.

вы можете сделать это так:

в AndroidManifest.xml

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

теперь в вашем коде:

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

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

На каждом устройстве Android есть как минимум интерфейс "wlan0", ведь это чип WI-FI.Этот код работает, даже когда WI-FI не включен.

PS Это множество других интерфейсов, которые вы получите из списка, содержащего MACS, но это может измениться между телефонами.

6 голосов
/ 07 июня 2016

Точнее, Settings.Secure.ANDROID_ID. Это 64-разрядная величина, которая генерируется и сохраняется при первой загрузке устройства. Сбрасывается при стирании устройства.

ANDROID_ID кажется хорошим выбором для уникального идентификатора устройства. Есть недостатки: во-первых, это не на 100% надежно в выпусках Android до 2.2 (“Froyo”). Кроме того, в популярном телефоне от одного крупного производителя была обнаружена, по крайней мере, одна широко распространенная ошибка, где каждый экземпляр имеет одинаковый ANDROID_ID .

6 голосов
/ 31 января 2013

Другой способ - использовать /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
  • Mini MK802
  • Samsung Galaxy S II

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

6 голосов
/ 15 апреля 2013

Я использую следующий код, чтобы получить IMEI или использовать Secure. ANDROID_ID в качестве альтернативы, когда устройство не имеет возможностей телефона:

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);
5 голосов
/ 03 октября 2016

идентификатор устройства Mac для Android также является уникальным идентификатором, он не изменится, если мы отформатируем само устройство, поэтому для получения идентификатора Mac используйте следующий код

WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
String address = info.getMacAddress();

Также не забудьте добавить соответствующие разрешения в ваш AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
5 голосов
/ 20 июня 2015

Идентификатор Google ID

Выпущено в I / O 2015; на Android требуются игровые сервисы 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

Похоже, Google намеревается использовать этот идентификатор для идентификации установок через Android, Chrome и iOS.

Он идентифицирует установку, а не устройство, но опять же, ANDROID_ID (который является принятым ответом) теперь больше не идентифицирует устройства. Во время выполнения ARC для каждой установки генерируется новый ANDROID_ID ( подробности здесь ), как и этот новый идентификатор экземпляра. Кроме того, я думаю, что большинство из нас на самом деле ищут определение установок (не устройств).

Преимущества экземпляра ID

Мне кажется, что Google намеревается использовать его для этой цели (с указанием ваших установок), он кроссплатформенный и может использоваться для ряда других целей (см. Ссылки выше).

Если вы используете GCM, то в конечном итоге вам понадобится использовать этот идентификатор экземпляра, потому что он нужен вам для получения токена GCM (который заменяет старый регистрационный идентификатор GCM).

Недостатки / проблемы

В текущей реализации (GPS 7.5) идентификатор экземпляра извлекается с сервера, когда ваше приложение запрашивает его. Это означает, что вышеуказанный вызов является блокирующим вызовом - в моем ненаучном тестировании это занимает 1-3 секунды, если устройство подключено к сети, и 0,5-1,0 секунды, если устройство находится в автономном режиме (предположительно, это то, сколько времени он ожидает, прежде чем сдаться и сгенерировать случайный идентификатор). Это было протестировано в Северной Америке на Nexus 5 с Android 5.1.1 и GPS 7.5.

Если вы используете ID для целей, для которых они предназначены - например. аутентификация приложения, идентификация приложения, GCM - я думаю, что эти 1-3 секунды могут быть неприятными (в зависимости от вашего приложения, конечно).

5 голосов
/ 06 февраля 2015

TelephonyManger.getDeviceId () Возвращает уникальный идентификатор устройства, например, IMEI для GSM и MEID или ESN для телефонов CDMA.

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

Но я рекомендую использовать:

Settings.Secure.ANDROID_ID , который возвращает идентификатор Android в виде уникальной 64-разрядной шестнадцатеричной строки.

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

Иногда TelephonyManger.getDeviceId () вернет ноль, поэтому для обеспечения уникального идентификатора вы будете использовать этот метод:

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;
}
4 голосов
/ 05 октября 2018

1.Вы можете получить доступ к идентификатору устройства Android с помощью службы gms. см. приведенный ниже пример,

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

2.Используйте диспетчер телефонии, который предоставляет уникальный идентификатор (т. Е. IMEI). Смотрите пример,

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

Это требует android.permission.READ_PHONE_STATE для вашего пользователя, что может быть трудно оправдать в зависимости от типа приложения, которое вы сделали.

  1. Устройства без служб телефонии, такие как планшеты, должны сообщать уникальный идентификатор устройства, который доступен через android.os.Build.SERIAL начиная с Android 2.3 Gingerbread. Некоторые телефоны, имеющие услуги телефонии, также могут определять серийный номер. Как не у всех Android-устройств есть серийный номер, это решение не является надежным.

  2. При первой загрузке устройства генерируется и сохраняется случайное значение. Это значение доступно через Settings.Secure.ANDROID_ID. Это 64-разрядное число, которое должно оставаться постоянным в течение всего срока службы устройства. ANDROID_ID кажется хорошим выбором для уникального идентификатора устройства, поскольку он доступен для смартфонов и планшетов. Чтобы получить значение, вы можете использовать следующий код,

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

Однако значение может измениться, если на устройстве выполнен сброс к заводским настройкам. Существует также известная ошибка с популярной трубкой от производителя, где каждый экземпляр имеет одинаковый ANDROID_ID. Очевидно, что решение не является надежным на 100%.

  1. Использовать UUID. Поскольку требование для большинства приложений состоит в том, чтобы идентифицировать конкретную установку, а не физическое устройство, хорошим решением является получение уникального идентификатора для пользователя, если использовать класс UUID. Следующее решение было представлено Рето Мейером из Google в презентации ввода / вывода Google,

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...