Вопрос: Есть ли уникальный идентификатор устройства Android?


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


2276


источник


Ответы:


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

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID); 

1659



ОБНОВИТЬ : Что касается последних версий Android, многие проблемы с ANDROID_IDбыли решены, и я считаю, что этот подход больше не нужен. Пожалуйста, взгляните на Ответ Антония ,

Полное раскрытие: мое приложение первоначально использовало подход ниже, но больше не использует этот подход, и теперь мы используем подход, описанный в Блог разработчика Android запись, которая Ответ emmby ссылки на (а именно, создание и сохранение UUID#randomUUID()).


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

Основываясь на моих тестах устройств (все телефоны, по крайней мере один из которых не активирован):

  1. Все тестируемые устройства вернули значение для TelephonyManager.getDeviceId()
  2. Все GSM-устройства (все протестированные с SIM-картой) вернули значение для TelephonyManager.getSimSerialNumber()
  3. Все устройства CDMA вернули значение null для getSimSerialNumber()(как и ожидалось)
  4. Все устройства с добавленной учетной записью Google вернули значение для ANDROID_ID
  5. Все устройства CDMA возвратили одно и то же значение (или вывод того же значения) для обоих ANDROID_IDа также TelephonyManager.getDeviceId()- так долго как во время установки была добавлена ​​учетная запись Google.
  6. У меня еще не было возможности протестировать GSM-устройства без SIM-карты, GSM-устройства без добавления аккаунта Google или любого из устройств в самолете.

Поэтому, если вы хотите что-то уникальное для самого устройства, TM.getDeviceId() должен быть достаточным. Очевидно, что некоторые пользователи более параноики, чем другие, поэтому было бы полезно хешировать один или несколько из этих идентификаторов, так что строка по-прежнему практически уникальна для устройства, но явно не идентифицирует фактическое устройство пользователя. Например, используя String.hashCode(), в сочетании с UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

может привести к чему-то вроде: 00000000-54b3-e7c7-0000-000046bffd97

Он работает достаточно хорошо для меня.

Как упоминает Ричард ниже, не забывайте, что вам нужно разрешение на чтение TelephonyManagerсвойства, поэтому добавьте это в свой манифест:

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

импортировать библиотеки

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;

1043



Последнее обновление: 6/2/15


После прочтения каждого сообщения Stack Overflow о создании уникального идентификатора, блога разработчика Google и документации для Android, я чувствую, что «Pseudo ID» - лучший вариант.

Основная проблема: аппаратное обеспечение и программное обеспечение

аппаратные средства

  • Пользователи могут менять свое оборудование, планшет или планшет Android, поэтому уникальные идентификаторы, основанные на оборудовании, не являются хорошими идеями для ОТСЛЕЖИВАНИЕ
  • Для ОБОРУДОВАНИЕ ДЛЯ ОТСЛЕЖИВАНИЯ , Эта великолепная идея

Программного обеспечения

  • Пользователи могут стереть / изменить свой ПЗУ, если они укоренены
  • Вы можете отслеживать пользователей на разных платформах (iOS, Android, Windows и Web)
  • Лучше всего ОТСУТСТВИЕ ИНДИВИДУАЛЬНОГО ПОЛЬЗОВАТЕЛЯ с их согласие просто попросить их войти (сделать это без использования OAuth)

Общая разбивка с Android

- Уникальность гарантии (включая внедренные устройства) для API> = 9/10 (99,5% устройств Android)

- Дополнительные разрешения

Псевдокод:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return unique ID of build information (may overlap data - API < 9)

Благодаря @stansult для публикации все наши варианты (в этом вопросе переполнения стека).

Список опций - причины, почему / почему не использовать их:

  • Электронная почта пользователя - программное обеспечение

  • Пользовательский номер телефона - Программное обеспечение

    • Пользователи могут менять номера телефонов - ВЫСОКО НЕВЕРОЯТНО
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Оборудование (только телефоны, потребности android.permission.READ_PHONE_STATE)

    • Большинство пользователей ненавидят тот факт, что в разрешении говорится «Телефонные звонки». Некоторые пользователи дают плохие оценки, потому что они считают, что вы просто крадете личную информацию, когда все, что вы действительно хотите сделать, это отслеживать установки устройств. Очевидно, что вы собираете данные.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android ID - Оборудование (может быть нулевым, может быть изменен при сбросе по заводской настройке, может быть изменен на корневом устройстве)

    • Поскольку это может быть «null», мы можем проверить «null» и изменить его значение, но это означает, что он больше не будет уникальным.
    • Если у вас есть устройство с заводским сбросом, значение может быть изменено или изменено на корневом устройстве, поэтому при записи пользовательских установок могут быть дубликаты записей.
  • MAC-адрес WLAN - аппаратное обеспечение (потребности android.permission.ACCESS_WIFI_STATE)

    • Это может быть вторым лучшим вариантом, но вы по-прежнему собираете и сохраняете уникальный идентификатор, который поступает непосредственно от пользователя. Очевидно, что вы собираете данные.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • MAC-адрес Bluetooth - аппаратное обеспечение (устройства с Bluetooth, потребности android.permission.BLUETOOTH)

    • Большинство приложений на рынке не используют Bluetooth, поэтому, если ваше приложение не использует Bluetooth, и вы включаете это, пользователь может стать подозрительным.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Псевдо-уникальный идентификатор - программное обеспечение (для всех Android-устройств)

    • Очень возможно, может содержать столкновения - см. Мой метод, который вы найдете ниже!
    • Это позволяет вам иметь «почти уникальный» идентификатор от пользователя, не принимая ничего личного. Вы можете создать свой анонимный идентификатор из информации об устройстве.

Я знаю, что нет «идеального» способа получения уникального идентификатора без использования разрешений; однако иногда нам действительно нужно отслеживать установку устройства. Когда дело доходит до создания уникального идентификатора, мы можем создать «псевдо уникальный идентификатор», основанный исключительно на информации, которую API Android дает нам, не используя дополнительных разрешений. Таким образом, мы можем показать уважение пользователей и попытаться предложить хороший пользовательский опыт.

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

API> = 9:

Если их Android-устройство - API 9 или более, это гарантированно будет уникальным из-за поля «Build.SERIAL».

ЗАПОМНИТЬ , вы технически только упускаете около 0,5% пользователей которые имеют API <9 , Таким образом, вы можете сосредоточиться на остальных: это 99,5% пользователей!

API <9:

Если Android-устройство пользователя ниже API 9; мы надеемся, что они не выполнили заводскую перезагрузку, и их «Secure.ANDROID_ID» будет сохранен или не «null». (видеть http://developer.android.com/about/dashboards/index.html )

Если все остальное не удается:

Если все остальное не удается, если пользователь имеет ниже API 9 (ниже Gingerbread), сбрасывает свое устройство, или «Secure.ANDROID_ID» возвращает «null», тогда просто возвращаемый идентификатор будет основываться исключительно на информации об устройстве Android. Здесь могут произойти столкновения.

Изменения:

  • Удаленный «Android.SECURE_ID» из-за заводских сбросов может привести к изменению значения
  • Отредактированный код для изменения API
  • Изменено псевдо

Пожалуйста, взгляните на приведенный ниже метод:

/**
 * Return pseudo unique ID
 * @return ID
 */
public static String getUniquePsuedoID() {
    // If all else fails, if the user does have lower than API 9 (lower
    // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
    // returns 'null', then simply the ID returned will be solely based
    // off their Android device information. This is where the collisions
    // can happen.
    // Thanks http://www.pocketmagic.net/?p=1662!
    // Try not to use DISPLAY, HOST or ID - these items could change.
    // If there are collisions, there will be overlapping data
    String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);

    // Thanks to @Roman SL!
    // https://stackoverflow.com/a/4789483/950427
    // Only devices with API >= 9 have android.os.Build.SERIAL
    // http://developer.android.com/reference/android/os/Build.html#SERIAL
    // If a user upgrades software or roots their device, there will be a duplicate entry
    String serial = null;
    try {
        serial = android.os.Build.class.getField("SERIAL").get(null).toString();

        // Go ahead and return the serial for api => 9
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        // String needs to be initialized
        serial = "serial"; // some value
    }

    // Thanks @Joe!
    // https://stackoverflow.com/a/2853253/950427
    // Finally, combine the values we have found by using the UUID class to create a unique identifier
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

Новое (для приложений с рекламой и сервисами Google Play):

С консоли Google Play Developers:

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

Реализация :

Разрешение:

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

Код:

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
...

// Do not call this function from the main thread. Otherwise, 
// an IllegalStateException will be thrown.
public void getIdThread() {

  Info adInfo = null;
  try {
    adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);

  } catch (IOException exception) {
    // Unrecoverable error connecting to Google Play services (e.g.,
    // the old version of the service doesn't support getting AdvertisingId).

  } catch (GooglePlayServicesAvailabilityException exception) {
    // Encountered a recoverable error connecting to Google Play services. 

  } catch (GooglePlayServicesNotAvailableException exception) {
    // Google Play services is not available entirely.
  }
  final String id = adInfo.getId();
  final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
}

Источник / Docs:

http://developer.android.com/google/play-services/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

Важный:

Предполагается, что рекламный идентификатор полностью заменяет существующие   использование других идентификаторов для целей рекламы (например, использование ANDROID_ID   в разделе «Настройки».), когда доступны службы Google Play. случаи   где службы Google Play недоступны, указывается   Ошибка GooglePlayServicesNotAvailableException.   getAdvertisingIdInfo ().

Предупреждение, пользователи могут выполнить сброс:

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

Я попытался ссылаться на каждую ссылку, из которой я взял информацию. Если вам не хватает и нужно включить, прокомментируйте!

Идентификатор экземпляра Служб Google Play

https://developers.google.com/instance-id/


352



Как упоминает Дейв Вебб, Блог разработчика 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 который сохраняется через перезагрузки приложений (но не для повторной установки приложения).

Обратите внимание, что для устройств, которые должны отступать от идентификатора устройства, уникальный идентификатор БУДЕМ сохраняются через заводские сбрасывания. Это то, о чем нужно знать. Если вам необходимо убедиться в том, что сброс на завод сбросит ваш уникальный идентификатор, вы можете захотеть вернуться обратно к случайному 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 volatile static UUID uuid;

    public DeviceUuidFactory(Context context) {
        if (uuid == null) {
            synchronized (DeviceUuidFactory.class) {
                if (uuid == null) {
                    final SharedPreferences prefs = context
                            .getSharedPreferences(PREFS_FILE, 0);
                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
                    if (id != null) {
                        // Use the ids previously computed and stored in the
                        // prefs file
                        uuid = UUID.fromString(id);
                    } else {
                        final String androidId = Secure.getString(
                            context.getContentResolver(), Secure.ANDROID_ID);
                        // Use the Android ID unless it's broken, in which case
                        // fallback on deviceId,
                        // unless it's not available, then fallback on a random
                        // number which we store to a prefs file
                        try {
                            if (!"9774d56d682e549c".equals(androidId)) {
                                uuid = UUID.nameUUIDFromBytes(androidId
                                        .getBytes("utf8"));
                            } else {
                                final String deviceId = (
                                    (TelephonyManager) context
                                    .getSystemService(Context.TELEPHONY_SERVICE))
                                    .getDeviceId();
                                uuid = deviceId != null ? UUID
                                    .nameUUIDFromBytes(deviceId
                                            .getBytes("utf8")) : UUID
                                    .randomUUID();
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                        // Write the value out to the prefs file
                        prefs.edit()
                                .putString(PREFS_DEVICE_ID, uuid.toString())
                                .commit();
                    }
                }
            }
        }
    }

    /**
     * Returns a unique UUID for the current android device. As with all UUIDs,
     * this unique ID is "very highly likely" to be unique across all Android
     * devices. Much more so than ANDROID_ID is.
     * 
     * The UUID is generated by using ANDROID_ID as the base key if appropriate,
     * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
     * be incorrect, and finally falling back on a random UUID that's persisted
     * to SharedPreferences if getDeviceID() does not return a usable value.
     * 
     * In some rare circumstances, this ID may change. In particular, if the
     * device is factory reset a new device ID may be generated. In addition, if
     * a user upgrades their phone from certain buggy implementations of Android
     * 2.2 to a newer, non-buggy version of Android, the device ID may change.
     * Or, if a user uninstalls your app on a device that has neither a proper
     * Android ID nor a Device ID, this ID may change on reinstallation.
     * 
     * Note that if the code falls back on using TelephonyManager.getDeviceId(),
     * the resulting ID will NOT change after a factory reset. Something to be
     * aware of.
     * 
     * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
     * directly.
     * 
     * @see http://code.google.com/p/android/issues/detail?id=10603
     * 
     * @return a UUID that may be used to uniquely identify your device for most
     *         purposes.
     */
    public UUID getDeviceUuid() {
        return uuid;
    }
}

314



Вот код, который Reto Meier использовал в Google I / O презентации в этом году, чтобы получить уникальный идентификатор для пользователя:

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

public synchronized static String id(Context context) {
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                PREF_UNIQUE_ID, Context.MODE_PRIVATE);
        uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
        if (uniqueID == null) {
            uniqueID = UUID.randomUUID().toString();
            Editor editor = sharedPrefs.edit();
            editor.putString(PREF_UNIQUE_ID, uniqueID);
            editor.commit();
        }
    }
    return uniqueID;
}

Если вы связали это с стратегией резервного копирования для отправки предпочтений облаку (также описано в Reto's говорить , у вас должен быть идентификатор, связанный с пользователем и зависающий после того, как устройство было вытерто или даже заменено. Я планирую использовать это в аналитике в будущем (другими словами, я еще не сделал этот бит :).


165



Также вы можете рассмотреть MAC-адрес адаптера Wi-Fi. Получено таким образом:

WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();

Требуется разрешение android.permission.ACCESS_WIFI_STATEв манифесте.

Сообщается, что он доступен, даже если Wi-Fi не подключен. Если Джо из приведенного выше ответа дает этому возможность попробовать свои многочисленные устройства, это было бы неплохо.

На некоторых устройствах он недоступен, когда Wi-Fi отключен.

ЗАМЕТКА: Начиная с Android 6.x, он возвращает постоянный поддельный адрес mac: 02:00:00:00:00:00


97



Есть довольно полезная информация Вот ,

Он охватывает пять различных типов идентификаторов:

  1. IMEI (только для устройств Android с использованием телефона; android.permission.READ_PHONE_STATE)
  2. Псевдо-уникальный идентификатор (для всех Android-устройств)
  3. Android ID (может быть нулевым, может меняться при сбросе настроек, может быть изменен на корневом телефоне)
  4. MAC-адрес WLAN строка (потребности android.permission.ACCESS_WIFI_STATE)
  5. BT MAC-адрес строка (устройства с Bluetooth, потребности android.permission.BLUETOOTH)

76



The official Android Developers Blog now has a full article just about this very subject, Identifying App Installations.


43